int BIO_dgram_sctp_wait_for_dry(BIO *b) { int is_dry = 0; int n, sockflags, ret; union sctp_notification snp; struct msghdr msg; struct iovec iov; #ifdef SCTP_EVENT struct sctp_event event; #else struct sctp_event_subscribe event; socklen_t eventsize; #endif bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; /* set sender dry event */ #ifdef SCTP_EVENT memset(&event, 0, sizeof(struct sctp_event)); event.se_assoc_id = 0; event.se_type = SCTP_SENDER_DRY_EVENT; event.se_on = 1; ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); #else eventsize = sizeof(struct sctp_event_subscribe); ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); if (ret < 0) return -1; event.sctp_sender_dry_event = 1; ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); #endif if (ret < 0) return -1; /* peek for notification */ memset(&snp, 0x00, sizeof(union sctp_notification)); iov.iov_base = (char *)&snp; iov.iov_len = sizeof(union sctp_notification); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; n = recvmsg(b->num, &msg, MSG_PEEK); if (n <= 0) { if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK)) return -1; else return 0; } /* if we find a notification, process it and try again if necessary */ while (msg.msg_flags & MSG_NOTIFICATION) { memset(&snp, 0x00, sizeof(union sctp_notification)); iov.iov_base = (char *)&snp; iov.iov_len = sizeof(union sctp_notification); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; n = recvmsg(b->num, &msg, 0); if (n <= 0) { if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK)) return -1; else return is_dry; } if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { is_dry = 1; /* disable sender dry event */ #ifdef SCTP_EVENT memset(&event, 0, sizeof(struct sctp_event)); event.se_assoc_id = 0; event.se_type = SCTP_SENDER_DRY_EVENT; event.se_on = 0; ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); #else eventsize = (socklen_t) sizeof(struct sctp_event_subscribe); ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); if (ret < 0) return -1; event.sctp_sender_dry_event = 0; ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); #endif if (ret < 0) return -1; } #ifdef SCTP_AUTHENTICATION_EVENT if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) dgram_sctp_handle_auth_free_key_event(b, &snp); #endif if (data->handle_notifications != NULL) data->handle_notifications(b, data->notification_context, (void*) &snp); /* found notification, peek again */ memset(&snp, 0x00, sizeof(union sctp_notification)); iov.iov_base = (char *)&snp; iov.iov_len = sizeof(union sctp_notification); msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; /* if we have seen the dry already, don't wait */ if (is_dry) { sockflags = fcntl(b->num, F_GETFL, 0); fcntl(b->num, F_SETFL, O_NONBLOCK); } n = recvmsg(b->num, &msg, MSG_PEEK); if (is_dry) { fcntl(b->num, F_SETFL, sockflags); } if (n <= 0) { if ((n < 0) && (get_last_socket_error() != EAGAIN) && (get_last_socket_error() != EWOULDBLOCK)) return -1; else return is_dry; } } /* read anything else */ return is_dry; }
static int send_netlink(struct nlmsghdr *hdr) { int s; pid_t mypid = getpid (); struct sockaddr_nl nl; struct iovec iov; struct msghdr msg; static unsigned int seq; char *buffer; int bytes; union { char *buffer; struct nlmsghdr *nlm; } h; if ((s = socket (AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) { logger (LOG_ERR, "socket: %s", strerror (errno)); return -1; } memset (&nl, 0, sizeof (struct sockaddr_nl)); nl.nl_family = AF_NETLINK; if (bind (s, (struct sockaddr *) &nl, sizeof (nl)) == -1) { logger (LOG_ERR, "bind: %s", strerror (errno)); close (s); return -1; } memset (&iov, 0, sizeof (struct iovec)); iov.iov_base = hdr; iov.iov_len = hdr->nlmsg_len; memset (&msg, 0, sizeof (struct msghdr)); msg.msg_name = &nl; msg.msg_namelen = sizeof (nl); msg.msg_iov = &iov; msg.msg_iovlen = 1; /* Request a reply */ hdr->nlmsg_flags |= NLM_F_ACK; hdr->nlmsg_seq = ++seq; if (sendmsg (s, &msg, 0) == -1) { logger (LOG_ERR, "write: %s", strerror (errno)); close (s); return -1; } buffer = xmalloc (sizeof (char) * BUFFERLEN); memset (buffer, 0, BUFFERLEN); iov.iov_base = buffer; while (1) { iov.iov_len = BUFFERLEN; bytes = recvmsg (s, &msg, 0); if (bytes == -1) { if (errno != EINTR) logger (LOG_ERR, "netlink: overrun"); continue; } if (bytes == 0) { logger (LOG_ERR, "netlink: EOF"); goto eexit; } if (msg.msg_namelen != sizeof (nl)) { logger (LOG_ERR, "netlink: sender address length mismatch"); goto eexit; } for (h.buffer = buffer; bytes >= (signed) sizeof (*h.nlm); ) { int len = h.nlm->nlmsg_len; int l = len - sizeof (*h.nlm); if (l < 0 || len > bytes) { if (msg.msg_flags & MSG_TRUNC) logger (LOG_ERR, "netlink: truncated message"); else logger (LOG_ERR, "netlink: malformed message"); goto eexit; } if (nl.nl_pid != 0 || (pid_t) h.nlm->nlmsg_pid != mypid || h.nlm->nlmsg_seq != seq) /* Message isn't for us, so skip it */ goto next; /* We get an NLMSG_ERROR back with a code of zero for success */ if (h.nlm->nlmsg_type == NLMSG_ERROR) { struct nlmsgerr *err = (struct nlmsgerr *) NLMSG_DATA (h.nlm); if ((unsigned) l < sizeof (struct nlmsgerr)) logger (LOG_ERR, "netlink: truncated error message"); else { errno = -err->error; if (errno == 0) { close (s); free (buffer); return 0; } /* Don't report on something already existing */ if (errno != EEXIST) logger (LOG_ERR, "netlink: %s", strerror (errno)); } goto eexit; } logger (LOG_ERR, "netlink: unexpected reply"); next: bytes -= NLMSG_ALIGN (len); h.buffer += NLMSG_ALIGN (len); } if (msg.msg_flags & MSG_TRUNC) { logger (LOG_ERR, "netlink: truncated message"); continue; } if (bytes) { logger (LOG_ERR, "netlink: remnant of size %d", bytes); goto eexit; } } eexit: close (s); free (buffer); return -1; }
void main(int argc, char * argv[]) { /* this program is command line tool to help us communicate with the kernel * it needs the following arguments to run: 1. filename_to_save_to, 2. message string or istead of "message string" have a -f tag, and then filename for input */ char * file_name; char message[MAX_NETCONNECT_INPUT]; char * input_file_name; FILE * input_file; FILE * file; FILE * bytes; char payload[MAX_PAYLOAD]; int payload_number = 0; int i; unsigned long recieved = 0; memset(message, 0, MAX_NETCONNECT_INPUT); if (argc != 3 && argc != 4) //thired argument is the programs name { //printf("Wrong parameters supplied. [LEAVING]\n"); return; } if (argc == 3) { //use regular input file_name = argv[1]; strncpy(message, argv[2], MAX_NETCONNECT_INPUT); } else if(argc == 4) { //check if -f tag given if (!strcmp(argv[2], FILE_TAG)) { input_file_name = argv[3]; input_file = fopen(input_file_name, "rt"); if (!input_file) { printf("WHAT"); } printf("GOT HERE\n"); cpy_from_file(input_file, message, MAX_NETCONNECT_INPUT); fclose(input_file); } } else {printf ("WRONG PARAMETERS SUPPLIED [LEAVING]\n"); return;} file_name = argv[1]; if (!strstr(file_name,".txt")) { printf("BAD parameters, file_name needs to be supplied with .txt ending.\n"); return; } file = fopen(file_name,"a+"); sock_fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_LISTEN_PROTOCOL); if (sock_fd < 0) return; memset(&src_addr, 0, sizeof(src_addr)); src_addr.nl_family = AF_NETLINK; src_addr.nl_pid = getpid(); /* self pid */ bind(sock_fd, (struct sockaddr *)&src_addr, sizeof(src_addr)); memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.nl_family = AF_NETLINK; dest_addr.nl_pid = 0; /* For Linux Kernel */ dest_addr.nl_groups = 0; /* unicast */ /* message header */ nlh = (struct nlmsghdr *)malloc(NLMSG_SPACE(MAX_PAYLOAD)); memset(nlh, 0, NLMSG_SPACE(MAX_PAYLOAD)); nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD); nlh->nlmsg_pid = getpid(); nlh->nlmsg_flags = 0; strcpy(NLMSG_DATA(nlh), message); iov.iov_base = (void *)nlh; iov.iov_len = nlh->nlmsg_len; msg.msg_name = (void *)&dest_addr; msg.msg_namelen = sizeof(dest_addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; printf("Letting kernel know our PID\n"); sendmsg(sock_fd, &msg, 0); printf("Waiting for report from kernel\n"); //delay to avoid rereading buffer recvmsg(sock_fd, &msg, 0); if (!strcmp(NLMSG_DATA(nlh),message)) { //delay -> and read again ignoring first recvmsg(sock_fd, &msg,0); printf("Buffer reread, avoiding crash...\n" ); } //check if empty if (strcmp(NLMSG_DATA(nlh),"EMPTY") == 0) { printf("No data to be read... [LEAVING]\n"); return; } payload_number = atoi(NLMSG_DATA(nlh)) / MAX_PAYLOAD; if (atoi(NLMSG_DATA(nlh)) % MAX_PAYLOAD != 0) { payload_number++; } save_read_bytes(bytes, NLMSG_DATA(nlh)); printf("Exepecting [%d] bytes in [%d] payloads\n", atoi(NLMSG_DATA(nlh)),payload_number); memset(payload, 0, MAX_PAYLOAD); memset(NLMSG_DATA(nlh), 0, MAX_PAYLOAD); for (i=0; i<payload_number; i++) { recvmsg(sock_fd, &msg, 0); strncpy(payload,NLMSG_DATA(nlh), MAX_PAYLOAD); recieved += strlen(payload); printf("Recieved [%d] bytes of total [%lu]\n",(int)strlen(payload), recieved); fprintf(file,"%s\n",payload); memset(NLMSG_DATA(nlh), 0, MAX_PAYLOAD); memset(payload, 0, MAX_PAYLOAD); } printf("OKAY [LEAVING]\n"); fclose(file); close(sock_fd); }
int main(int argc, char *argv[]) { printf("SOCK_RAW=%u\n", SOCK_RAW); printf("SOCK_STREAM=%u\n", SOCK_STREAM); printf("SOCK_DGRAM=%u\n", SOCK_DGRAM); printf("IPPROTO_ICMP=%u\n", IPPROTO_ICMP); printf("IPPROTO_TCP=%u\n", IPPROTO_TCP); printf("IPPROTO_IP=%u\n", IPPROTO_IP); int sock; struct sockaddr_in server_addr; struct sockaddr_in client_addr; int addr_len = sizeof(struct sockaddr); int numbytes; //struct hostent *host; int send_len = 200000; char send_data[send_len + 24]; int port; int client_port; pid_t pID; memset(send_data, 89, send_len); send_data[send_len] = '\0'; //host= (struct hostent *) gethostbyname((char *)"127.0.0.1"); //if ((sock = socket(PF_INET, SOCK_RAW, IPPROTO_UDP)) == -1) { //if ((sock = socket(PF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0)) == -1) { if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { perror("socket"); exit(1); } int val = 0; setsockopt(sock, SOL_IP, IP_MTU_DISCOVER, &val, sizeof(val)); val = 1; setsockopt(sock, SOL_SOCKET, SO_TIMESTAMP, &val, sizeof(val)); val = 1; setsockopt(sock, SOL_IP, IP_RECVTTL, &val, sizeof(val)); val = 1; setsockopt(sock, SOL_IP, IP_RECVERR, &val, sizeof(val)); //fcntl64(3, F_SETFL, O_RDONLY|O_NONBLOCK) = 0 //fstat64(1, {st_dev=makedev(0, 11), st_ino=3, st_mode=S_IFCHR|0620, st_nlink=1, st_uid=1000, st_gid=5, st_blksize=1024, st_blocks=0, st_rdev=makedev(136, 0), st_atime=2012/10/16-22:31:09, st_mtime=2012/10/16-22:31:09, st_ctime=2012/10/16-19:33:02}) = 0 val = 3; setsockopt(sock, SOL_IP, IP_TTL, &val, sizeof(val)); if (argc > 1) { port = atoi(argv[1]); } else { port = 45454; } printf("MY DEST PORT BEFORE AND AFTER\n"); printf("%d, %d\n", port, htons(port)); fflush(stdout); server_addr.sin_family = PF_INET; server_addr.sin_port = htons(port); //server_addr.sin_port = htons(53); server_addr.sin_addr.s_addr = xxx(192,168,1,5); //server_addr.sin_addr.s_addr = xxx(127,0,0,1); //server_addr.sin_addr.s_addr = xxx(74,125,224,72); //server_addr.sin_addr.s_addr = INADDR_LOOPBACK; server_addr.sin_addr.s_addr = htonl(server_addr.sin_addr.s_addr); bzero(&(server_addr.sin_zero), 8); printf("\n UDP Client sending to server at server_addr=%s:%d, netw=%u\n", inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port), server_addr.sin_addr.s_addr); fflush(stdout); if (argc > 2) { client_port = atoi(argv[2]); } else { client_port = 55555; } client_addr.sin_family = PF_INET; client_addr.sin_port = htons(client_port); //client_addr.sin_addr.s_addr = xxx(127,0,0,1); client_addr.sin_addr.s_addr = INADDR_ANY; //client_addr.sin_addr.s_addr = INADDR_LOOPBACK; client_addr.sin_addr.s_addr = htonl(client_addr.sin_addr.s_addr); //bzero(&(client_addr.sin_zero), 8); printf("Binding to client_addr=%s:%d, netw=%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), client_addr.sin_addr.s_addr); fflush(stdout); if (bind(sock, (struct sockaddr *) &client_addr, sizeof(struct sockaddr_in)) == -1) { perror("Bind"); printf("Failure"); exit(1); } printf("Bound to client_addr=%s:%d, netw=%u\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), client_addr.sin_addr.s_addr); fflush(stdout); int nfds = 2; struct pollfd fds[nfds]; fds[0].fd = -1; fds[0].events = POLLIN | POLLERR; //| POLLPRI; fds[1].fd = sock; fds[1].events = POLLIN | 0; //fds[1].events = POLLIN | POLLPRI | POLLOUT | POLLERR | POLLHUP | POLLNVAL | POLLRDNORM | POLLRDBAND | POLLWRNORM | POLLWRBAND; printf("\n fd: sock=%d, events=%x\n", sock, fds[1].events); fflush(stdout); int time = 1000; //pID = fork(); if (pID == 0) { // child -- Capture process send_data[0] = 65; } else if (pID < 0) { // failed to fork printf("Failed to Fork \n"); fflush(stdout); exit(1); } else { //parent send_data[0] = 89; } int ret = 0; struct msghdr recv_msg; int name_len = 64; char name_buf[name_len]; struct iovec iov[1]; int recv_len = 1000; char recv_buf[recv_len]; int control_len = 4000; char control_buf[control_len]; iov[0].iov_len = recv_len; iov[0].iov_base = recv_buf; recv_msg.msg_namelen = name_len; recv_msg.msg_name = name_buf; recv_msg.msg_iovlen = 1; recv_msg.msg_iov = iov; recv_msg.msg_controllen = control_len; recv_msg.msg_control = control_buf; struct cmsghdr *cmsg; int *ttlptr; int received_ttl; struct timeval curr; struct timeval *stamp; if (0) { int len; int i = 0; while (1) { i++; if (1) { printf("(%d) Input msg (q or Q to quit):", i); fflush(stdout); gets(send_data); //len = strlen(send_data); len = 1000; printf("\nlen=%d, str='%s'\n", len, send_data); fflush(stdout); if (len > 0 && len < send_len) { gettimeofday(&curr, 0); numbytes = sendto(sock, send_data, len, 0, (struct sockaddr *) &server_addr, sizeof(struct sockaddr_in)); //sleep(1); ret = poll(fds, nfds, time); if (ret || 0) { if (1) { printf("poll: ret=%d, revents=%x\n", ret, fds[ret].revents); printf( "POLLIN=%x POLLPRI=%x POLLOUT=%x POLLERR=%x POLLHUP=%x POLLNVAL=%x POLLRDNORM=%x POLLRDBAND=%x POLLWRNORM=%x POLLWRBAND=%x\n", (fds[ret].revents & POLLIN) > 0, (fds[ret].revents & POLLPRI) > 0, (fds[ret].revents & POLLOUT) > 0, (fds[ret].revents & POLLERR) > 0, (fds[ret].revents & POLLHUP) > 0, (fds[ret].revents & POLLNVAL) > 0, (fds[ret].revents & POLLRDNORM) > 0, (fds[ret].revents & POLLRDBAND) > 0, (fds[ret].revents & POLLWRNORM) > 0, (fds[ret].revents & POLLWRBAND) > 0); fflush(stdout); } int recv_bytes; if ((fds[ret].revents & (POLLERR)) || 0) { recv_bytes = recvmsg(sock, &recv_msg, MSG_ERRQUEUE); if (recv_bytes > 0) { printf("recv_bytes=%d, msg_controllen=%d\n", recv_bytes, recv_msg.msg_controllen); /* Receive auxiliary data in msgh */ for (cmsg = CMSG_FIRSTHDR(&recv_msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&recv_msg, cmsg)) { printf("cmsg_len=%u, cmsg_level=%u, cmsg_type=%u\n", cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type); if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) { received_ttl = *(int *) CMSG_DATA(cmsg); printf("received_ttl=%d\n", received_ttl); //break; } else if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR) { struct sock_extended_err *err = (struct sock_extended_err *) CMSG_DATA(cmsg); printf("ee_errno=%u, ee_origin=%u, ee_type=%u, ee_code=%u, ee_pad=%u, ee_info=%u, ee_data=%u\n", err->ee_errno, err->ee_origin, err->ee_type, err->ee_code, err->ee_pad, err->ee_info, err->ee_data); struct sockaddr_in *offender = (struct sockaddr_in *) SO_EE_OFFENDER(err); printf("family=%u, addr=%s/%u\n", offender->sin_family, inet_ntoa(offender->sin_addr), ntohs(offender->sin_port)); } else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) { struct timeval *stamp = (struct timeval *) CMSG_DATA(cmsg); printf("stamp=%u.%u\n", (uint32_t) stamp->tv_sec, (uint32_t) stamp->tv_usec); printf("diff=%f\n", time_diff(&curr, stamp)); } } if (cmsg == NULL) { /* * Error: IP_TTL not enabled or small buffer * or I/O error. */ } } else { printf("errno=%d\n", errno); perror("recvmsg"); } } else if ((fds[ret].revents & (POLLIN | POLLRDNORM)) || 0) { recv_bytes = recvmsg(sock, &recv_msg, 0); if (recv_bytes > 0) { printf("recv_bytes=%d, msg_controllen=%d\n", recv_bytes, recv_msg.msg_controllen); /* Receive auxiliary data in msgh */ for (cmsg = CMSG_FIRSTHDR(&recv_msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&recv_msg, cmsg)) { printf("cmsg_len=%u, cmsg_level=%u, cmsg_type=%u\n", cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type); if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_TTL) { received_ttl = *(int *) CMSG_DATA(cmsg); printf("received_ttl=%d\n", received_ttl); //break; } else if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP) { struct timeval *stamp = (struct timeval *) CMSG_DATA(cmsg); } } if (cmsg == NULL) { /* * Error: IP_TTL not enabled or small buffer * or I/O error. */ } } } } } else { printf("Error string len, len=%d\n", len); } } if (0) { if (pID == 0) { numbytes = sendto(sock, send_data, 1, 0, (struct sockaddr *) &server_addr, sizeof(struct sockaddr_in)); printf("\n sent=%d", numbytes); numbytes = sendto(sock, send_data, 1, 0, (struct sockaddr *) &server_addr, sizeof(struct sockaddr_in)); printf("\n sent=%d", numbytes); } else { //numbytes = recvfrom(sock, send_data, 1024, 0, (struct sockaddr *) &client_addr, &addr_len); printf("\n read=%d", numbytes); } fflush(stdout); } if ((strcmp(send_data, "q") == 0) || strcmp(send_data, "Q") == 0) { break; } } } if (1) { struct timeval start, end; int its = 10;//10000; int data_len = 1000; while (data_len < 4000) { gets(send_data); //data_len += 100; //data_len = 1000; int total_bytes = 0; double total_time = 0; int total_success = 0; double diff; int i = 0; while (i < its) { i++; gettimeofday(&start, 0); numbytes = sendto(sock, send_data, data_len, 0, (struct sockaddr *) &server_addr, sizeof(struct sockaddr)); gettimeofday(&end, 0); diff = time_diff(&start, &end); if (numbytes > 0) { total_success++; total_bytes += numbytes; total_time += diff; } //usleep(100); } //printf("\n diff=%f, len=%d, avg=%f ms, calls=%f, bits=%f", diff, data_len, diff / its, 1000 / (diff / its), 1000 / (diff / its) * data_len); printf("\n len=%d, time=%f, suc=%d, bytes=%d, avg=%f ms, eff=%f, thr=%f, calls=%f, act=%f", data_len, total_time, total_success, total_bytes, total_time / total_success, total_success / (double) its, total_bytes / (double) its / data_len, 1000 / (total_time / total_success), 1000 / (total_time / total_success) * data_len * 8); fflush(stdout); //sleep(5); } } if (0) { int i = 0; int its = 10000; double speed = 15000000; int len = 1000; double time = 8 * len / speed * 1000000; int use = (int) (time + .5);//ceil(time); printf("time=%f, used=%u\n", time, use); fflush(stdout); int *data = (int *) send_data; *(data + 1) = 0; double diff; struct timeval start, end; gettimeofday(&start, 0); while (1) { *data = htonl(i); numbytes = sendto(sock, send_data, len, 0, (struct sockaddr *) &server_addr, sizeof(struct sockaddr_in)); if (numbytes != len) { break; } if (1) { gettimeofday(&end, 0); diff = time_diff(&start, &end) / 1000; printf("time=%f, frames=%d, speed=%f\n", diff, i, 8 * len * i / diff); fflush(stdout); } i++; //usleep(use); } } printf("\n Closing socket"); fflush(stdout); close(sock); printf("\n FIN"); fflush(stdout); while (1) ; return 0; }
void rxpacket(int sock) { Packet pkt; memset(&pkt, 0, sizeof(pkt)); // using recvmsg int size; // size of the received data struct msghdr msg; memset(&msg, 0, sizeof(msg)); struct sockaddr_in from; int fromlen=sizeof(from); msg.msg_name = &from; msg.msg_namelen = fromlen; char anciliary[2048]; msg.msg_control = anciliary; msg.msg_controllen = sizeof(anciliary); struct iovec iov[1]; memset(iov, 0, sizeof(iov)); iov[0].iov_base = &pkt.data; iov[0].iov_len = sizeof(pkt.data); msg.msg_iov = iov; msg.msg_iovlen = 1; struct cmsghdr *cmsg; unsigned int ifindex; // interface index struct in_addr hdraddr; // destination IP address in IP header size = recvmsg(sock, &msg, 0); if (size == -1) { ASSERT(0); rcpLog(muxsock, RCP_PROC_RIP, RLOG_ERR, RLOG_FC_RIP, "cannot read data on socket, attempting recovery..."); exit(1); } // verify packet size int sz = size - 4; if (sz<= 0 || (sz % sizeof(RipRoute)) != 0) { rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, "Invalid RIP packet size"); return; } int routes = sz / sizeof(RipRoute); int found = 0; for(cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { // struct in_pktinfo { // unsigned int ipi_ifindex; /* Interface index */ // struct in_addr ipi_spec_dst; /* Local address */ // struct in_addr ipi_addr; /* Header Destination // address */ // }; hdraddr = ((struct in_pktinfo*)CMSG_DATA(cmsg))->ipi_addr; ifindex = ((struct in_pktinfo*)CMSG_DATA(cmsg))->ipi_ifindex; found = 1; } } if (!found) return; pkt.ip_source = ntohl(from.sin_addr.s_addr); pkt.ip_dest = ntohl(hdraddr.s_addr); pkt.if_index = ifindex; // is the source ip address one of our addresses? RcpInterface *rxif = rcpFindInterface(shm, pkt.ip_source); if (rxif) { // on Linux, packets we send to the multicast group will be received back on the socket return; } char *cmd[] = {"", "request", "response"}; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, "Receiving RIP packet of size %d, from %d.%d.%d.%d, destination %d.%d.%d.%d, RIP %s, protocol version %d", size, RCP_PRINT_IP(pkt.ip_source), RCP_PRINT_IP(pkt.ip_dest), cmd[(pkt.data.command <= 2) ? pkt.data.command: 0], pkt.data.version); // update neighbor list RipNeighbor *neigh = neighbors; while (neigh != NULL) { if (neigh->ip == pkt.ip_source) { neigh->rx_time = 0; break; } neigh = neigh->next; } if (neigh == NULL) { RipNeighbor *newneigh = malloc(sizeof(RipNeighbor)); if (newneigh != NULL) { memset(newneigh, 0, sizeof(RipNeighbor)); newneigh->ip = pkt.ip_source; newneigh->next = neighbors; neighbors = newneigh; neigh = newneigh; } else { ASSERT(0); rcpLog(muxsock, RCP_PROC_RIP, RLOG_ERR, RLOG_FC_RIP, "cannot allocate memory, attempting recovery..."); exit(1); } } // do we have a valid interface? rxif =rcpFindInterfaceByKIndex(shm, pkt.if_index); if (rxif == NULL) { neigh->errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid interface, dropping..."); return; } // do we have a configured neighbor? RcpRipPartner *rxnetwork = NULL; RcpRipPartner *net; int i; for (i = 0, net = shm->config.rip_neighbor; i < RCP_RIP_NEIGHBOR_LIMIT; i++, net++) { if (!net->valid) continue; // matching both source and destination addresses if (net->ip == pkt.ip_source && rxif->ip == pkt.ip_dest) { rxnetwork = net; break; } } // if no configured neighbor was found, try to find a configured network if (rxnetwork == NULL) rxnetwork = find_network_for_interface(rxif); // no network or neighbor configured, just drop the packet if (rxnetwork == NULL) { neigh->errors++; // the network can get disabled while receiving packets rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid network or neighbor, dropping..."); return; } // the source of the datagram must be on a directly-connected network if ((pkt.ip_source & rxif->mask) != (rxif->ip & rxif->mask)) { neigh->errors++; // interface ip addresses are changing dynamically via CLI rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid source IP address, dropping..."); return; } // drop invalid command packets if (pkt.data.command > 2) { neigh->errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid RIP command, dropping..."); return; } if (pkt.data.command == 1) { rxnetwork->req_rx++; // force a response in one second rxif->rip_timeout = 1; return; } else rxnetwork->resp_rx++; ASSERT(sizeof(RipAuthMd5) == sizeof(RipAuthSimple)); ASSERT(sizeof(RipAuthSimple) == sizeof(RipRoute)); RipRoute *ptr = &pkt.data.routes[0]; int rt = 0; // if md5 auth configured, and the packet is missing the auth header, drop the packet if (rxif->rip_passwd[0] != '\0') { if (ptr->family != 0xffff || ntohs(ptr->tag) != 3) { neigh->md5_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " missing MD5 authentication header"); return; } } // checking auth header and calculate md5 if (ptr->family == 0xffff) { // we don't care about simple auth if (ntohs(ptr->tag) == 3 && rxif->rip_passwd[0] != '\0') { RipAuthMd5 *md5 = (RipAuthMd5 *) ptr; uint16_t offset = ntohs(md5->offset); uint32_t seq = ntohl(md5->seq); rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " MD5 auth offset %u, key id %d, auth_len %d, seq %u", offset, md5->key_id, md5->auth_len, ntohl(md5->seq)); // check offset if ((offset + sizeof(RipRoute)) != size) { neigh->md5_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid offset"); return; } // check seq if (seq != 0 && seq < neigh->auth_seq) { neigh->md5_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid sequence number"); return; } neigh->auth_seq = seq; // calculate md5 uint8_t secret[16]; memset(secret, 0, 16); memcpy(secret, rxif->rip_passwd, strlen(rxif->rip_passwd)); MD5_CTX context; uint8_t digest[16]; MD5Init (&context); MD5Update (&context, (uint8_t *) &pkt, size - 16); MD5Update (&context, secret, 16); MD5Final (digest, &context); #if 0 { int i; uint8_t *p = digest; printf("rx digest:\n"); for (i = 0; i < 16; i++,p++) printf("%02x ", *p); printf("\n"); } #endif // compare md5 if (memcmp((uint8_t *) ptr + offset, digest, 16) != 0) { neigh->md5_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid MD5 digest"); return; } } ptr++; rt++; routes--; // the last route is the digest } // parsing routes while (rt < routes) { uint32_t metric = ntohl(ptr->metric); uint32_t mask = ntohl(ptr->mask); uint32_t ip = ntohl(ptr->ip); uint32_t gw = ntohl(ptr->gw); // if (trace_prefix == 0 || // (trace_prefix != 0 && trace_prefix == ip)) { // if (gw == 0) // rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, // " %d.%d.%d.%d/%d metric %u", // RCP_PRINT_IP(ip), // mask2bits(mask), // metric); // else // rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, // " %d.%d.%d.%d/%d metric %u next hop %d.%d.%d.%d", // RCP_PRINT_IP(ip), // mask2bits(mask), // metric, // RCP_PRINT_IP(gw)); // } // only AF_INET family is supported if (ntohs(ptr->family) != AF_INET) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid route family"); goto next_element; } // check destination for loopback addresses if (isLoopback(ip)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid loopback route prefix"); goto next_element; } // check destination for broadcast addresses if (isBroadcast(ip)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid broadcast route prefix"); goto next_element; } // check destination for multicast addresses if (isMulticast(ip)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid multicast route prefix"); goto next_element; } // validate route metric else if (metric > 16 || metric == 0) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid metric"); goto next_element; } // validate route entry if (ip == 0 && mask == 0) { rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " received default route metric %d", metric); } else if (pkt.data.version == 2 && mask == 0) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid RIP route"); goto next_element; } else if (pkt.data.version == 1 && mask != 0) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid RIP route"); goto next_element; } // check if the mask is contiguous if (mask != 0 && !maskContiguous(mask)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid mask"); goto next_element; } // validate next hop if (gw) { if (isLoopback(gw) || isMulticast(gw) || isBroadcast(gw)) { neigh->route_errors++; rcpLog(muxsock, RCP_PROC_RIP, RLOG_DEBUG, RLOG_FC_RIP, " invalid next hop"); goto next_element; } } // manufacture mask for rip v1 if (pkt.data.version == 1) mask = classMask(ip); // RFC metric = metric + interface cost // we assume a cost of 1 for each interface metric++; // add the route in the database if (metric < 16) { //RFC //- Setting the destination address to the destination address in the // RTE // // - Setting the metric to the newly calculated metric (as described // above) // // - Set the next hop address to be the address of the router from which // the datagram came // // - Initialize the timeout for the route. If the garbage-collection // timer is running for this route, stop it (see section 3.6 for a // discussion of the timers) // // - Set the route change flag // // - Signal the output process to trigger an update (see section 3.8.1) // a next hop of 0 means send the packets to me if (gw == 0) gw = pkt.ip_source; ripdb_add(RCP_ROUTE_RIP, ip, mask, gw, metric, pkt.ip_source, rxif); } else { // a next hop of 0 means send the packets to me if (gw == 0) gw = pkt.ip_source; ripdb_delete(RCP_ROUTE_RIP, ip, mask, gw, pkt.ip_source); } next_element: ptr++; rt++; } }
static void uv__udp_recvmsg(uv_loop_t* loop, uv__io_t* w, unsigned int revents) { struct sockaddr_storage peer; struct msghdr h; uv_udp_t* handle; ssize_t nread; uv_buf_t buf; int flags; int count; handle = container_of(w, uv_udp_t, io_watcher); assert(handle->type == UV_UDP); assert(revents & UV__POLLIN); assert(handle->recv_cb != NULL); assert(handle->alloc_cb != NULL); /* Prevent loop starvation when the data comes in as fast as (or faster than) * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. */ count = 32; memset(&h, 0, sizeof(h)); h.msg_name = &peer; do { buf = handle->alloc_cb((uv_handle_t*)handle, 64 * 1024); assert(buf.len > 0); assert(buf.base != NULL); h.msg_namelen = sizeof(peer); h.msg_iov = (void*) &buf; h.msg_iovlen = 1; do { nread = recvmsg(handle->io_watcher.fd, &h, 0); } while (nread == -1 && errno == EINTR); if (nread == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { uv__set_sys_error(handle->loop, EAGAIN); handle->recv_cb(handle, 0, buf, NULL, 0); } else { uv__set_sys_error(handle->loop, errno); handle->recv_cb(handle, -1, buf, NULL, 0); } } else { flags = 0; if (h.msg_flags & MSG_TRUNC) flags |= UV_UDP_PARTIAL; handle->recv_cb(handle, nread, buf, (struct sockaddr*)&peer, flags); } } /* recv_cb callback may decide to pause or close the handle */ while (nread != -1 && count-- > 0 && handle->io_watcher.fd != -1 && handle->recv_cb != NULL); }
static int recv_fd(int c) { int fd; uint8_t msgbuf[CMSG_SPACE(sizeof(fd))]; struct msghdr msg = { .msg_control = msgbuf, .msg_controllen = sizeof(msgbuf), }; struct cmsghdr *cmsg; struct iovec iov; uint8_t req[1]; ssize_t len; cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(sizeof(fd)); msg.msg_controllen = cmsg->cmsg_len; iov.iov_base = req; iov.iov_len = sizeof(req); msg.msg_iov = &iov; msg.msg_iovlen = 1; len = recvmsg(c, &msg, 0); if (len > 0) { memcpy(&fd, CMSG_DATA(cmsg), sizeof(fd)); return fd; } return len; } static int net_bridge_run_helper(const char *helper, const char *bridge) { sigset_t oldmask, mask; int pid, status; char *args[5]; char **parg; int sv[2]; sigemptyset(&mask); sigaddset(&mask, SIGCHLD); sigprocmask(SIG_BLOCK, &mask, &oldmask); if (socketpair(PF_UNIX, SOCK_STREAM, 0, sv) == -1) { return -1; } /* try to launch bridge helper */ pid = fork(); if (pid == 0) { int open_max = sysconf(_SC_OPEN_MAX), i; char fd_buf[6+10]; char br_buf[6+IFNAMSIZ] = {0}; char helper_cmd[PATH_MAX + sizeof(fd_buf) + sizeof(br_buf) + 15]; for (i = 0; i < open_max; i++) { if (i != STDIN_FILENO && i != STDOUT_FILENO && i != STDERR_FILENO && i != sv[1]) { close(i); } } snprintf(fd_buf, sizeof(fd_buf), "%s%d", "--fd=", sv[1]); if (strrchr(helper, ' ') || strrchr(helper, '\t')) { /* assume helper is a command */ if (strstr(helper, "--br=") == NULL) { snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge); } snprintf(helper_cmd, sizeof(helper_cmd), "%s %s %s %s", helper, "--use-vnet", fd_buf, br_buf); parg = args; *parg++ = (char *)"sh"; *parg++ = (char *)"-c"; *parg++ = helper_cmd; *parg++ = NULL; execv("/bin/sh", args); } else { /* assume helper is just the executable path name */ snprintf(br_buf, sizeof(br_buf), "%s%s", "--br=", bridge); parg = args; *parg++ = (char *)helper; *parg++ = (char *)"--use-vnet"; *parg++ = fd_buf; *parg++ = br_buf; *parg++ = NULL; execv(helper, args); } _exit(1); } else if (pid > 0) { int fd; close(sv[1]); do { fd = recv_fd(sv[0]); } while (fd == -1 && errno == EINTR); close(sv[0]); while (waitpid(pid, &status, 0) != pid) { /* loop */ } sigprocmask(SIG_SETMASK, &oldmask, NULL); if (fd < 0) { fprintf(stderr, "failed to recv file descriptor\n"); return -1; } if (WIFEXITED(status) && WEXITSTATUS(status) == 0) { return fd; } } fprintf(stderr, "failed to launch bridge helper\n"); return -1; }
static int sco_ipc_cmd(uint8_t service_id, uint8_t opcode, uint16_t len, void *param, size_t *rsp_len, void *rsp, int *fd) { ssize_t ret; struct msghdr msg; struct iovec iv[2]; struct ipc_hdr cmd; char cmsgbuf[CMSG_SPACE(sizeof(int))]; struct ipc_status s; size_t s_len = sizeof(s); pthread_mutex_lock(&sk_mutex); if (ipc_sk < 0) { error("sco: Invalid cmd socket passed to sco_ipc_cmd"); goto failed; } if (!rsp || !rsp_len) { memset(&s, 0, s_len); rsp_len = &s_len; rsp = &s; } memset(&msg, 0, sizeof(msg)); memset(&cmd, 0, sizeof(cmd)); cmd.service_id = service_id; cmd.opcode = opcode; cmd.len = len; iv[0].iov_base = &cmd; iv[0].iov_len = sizeof(cmd); iv[1].iov_base = param; iv[1].iov_len = len; msg.msg_iov = iv; msg.msg_iovlen = 2; ret = sendmsg(ipc_sk, &msg, 0); if (ret < 0) { error("sco: Sending command failed:%s", strerror(errno)); goto failed; } /* socket was shutdown */ if (ret == 0) { error("sco: Command socket closed"); goto failed; } memset(&msg, 0, sizeof(msg)); memset(&cmd, 0, sizeof(cmd)); iv[0].iov_base = &cmd; iv[0].iov_len = sizeof(cmd); iv[1].iov_base = rsp; iv[1].iov_len = *rsp_len; msg.msg_iov = iv; msg.msg_iovlen = 2; if (fd) { memset(cmsgbuf, 0, sizeof(cmsgbuf)); msg.msg_control = cmsgbuf; msg.msg_controllen = sizeof(cmsgbuf); } ret = recvmsg(ipc_sk, &msg, 0); if (ret < 0) { error("sco: Receiving command response failed:%s", strerror(errno)); goto failed; } if (ret < (ssize_t) sizeof(cmd)) { error("sco: Too small response received(%zd bytes)", ret); goto failed; } if (cmd.service_id != service_id) { error("sco: Invalid service id (%u vs %u)", cmd.service_id, service_id); goto failed; } if (ret != (ssize_t) (sizeof(cmd) + cmd.len)) { error("sco: Malformed response received(%zd bytes)", ret); goto failed; } if (cmd.opcode != opcode && cmd.opcode != SCO_OP_STATUS) { error("sco: Invalid opcode received (%u vs %u)", cmd.opcode, opcode); goto failed; } if (cmd.opcode == SCO_OP_STATUS) { struct ipc_status *s = rsp; if (sizeof(*s) != cmd.len) { error("sco: Invalid status length"); goto failed; } if (s->code == SCO_STATUS_SUCCESS) { error("sco: Invalid success status response"); goto failed; } pthread_mutex_unlock(&sk_mutex); return s->code; } pthread_mutex_unlock(&sk_mutex); /* Receive auxiliary data in msg */ if (fd) { struct cmsghdr *cmsg; *fd = -1; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { memcpy(fd, CMSG_DATA(cmsg), sizeof(int)); break; } } if (*fd < 0) goto failed; } if (rsp_len) *rsp_len = cmd.len; return SCO_STATUS_SUCCESS; failed: /* Some serious issue happen on IPC - recover */ shutdown(ipc_sk, SHUT_RDWR); pthread_mutex_unlock(&sk_mutex); return SCO_STATUS_FAILED; }
static inline int ufw_recv(ufw_sk *sk){ struct cmsghdr* cmsg; char ctlbuf[4096]; struct iovec iov; struct msghdr msg = {NULL, 0, &iov, 1, ctlbuf, sizeof(ctlbuf), 0}; ssize_t s; struct node *cur; struct hookinfo *hki; struct timeval time; struct iphdr *ip; if(!sk){ errno = EBADF; return -1; } iov.iov_base = sk->recvbuf; iov.iov_len = sizeof(sk->recvbuf); ip = (struct iphdr *)sk->recvbuf; for(;;){ next: s = recvmsg(sk->fd, &msg, MSG_WAITALL); if(s < 0){ if(errno == EAGAIN) return 0; else { if(sk->opts & FATAL)die("recvmsg"); return -1; } } /* filter */ if((sk->opts & FILTER_SADDR) && ip->daddr != sk->saddr) continue; if((sk->opts & FILTER_DADDR) && ip->saddr != sk->daddr) continue; if((sk->opts & FILTER_SPORT) && *(u_int16_t *)(sk->recvbuf + (ip->ihl << 2) + 2) != sk->sport) continue; if((sk->opts & FILTER_DPORT) && *(u_int16_t *)(sk->recvbuf + (ip->ihl << 2)) != sk->dport) continue; sk->received = 1; /* get timestamp */ for(cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) if(cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SO_TIMESTAMP && cmsg->cmsg_len >= CMSG_LEN(sizeof(struct timeval))){ time = *(struct timeval *)CMSG_DATA(cmsg); break; } if(!sk->first_packet.tv_sec) sk->first_packet = time; for(cur = sk->recvhook; cur; cur = cur->next){ hki = cur->data; if(!hki->func(sk->recvbuf, &time, 1, hki->user)) goto next; } if((sk->opts & DUMP_RECV) && sk->dump) dump_write(sk->dump, sk->recvbuf, 0, &time); time.tv_sec -= sk->first_packet.tv_sec; time.tv_usec -= sk->first_packet.tv_usec; if(time.tv_usec < 0)time.tv_usec += 1000000; if(sk->opts & PRINT_RECV) print_packet(sk->recvbuf, &time, 0); } return -1;//never }
ssize_t pa_iochannel_read_with_ancil_data(pa_iochannel*io, void*data, size_t l, pa_cmsg_ancil_data *ancil_data) { ssize_t r; struct msghdr mh; struct iovec iov; union { struct cmsghdr hdr; uint8_t data[CMSG_SPACE(sizeof(struct ucred)) + CMSG_SPACE(sizeof(int) * MAX_ANCIL_DATA_FDS)]; } cmsg; pa_assert(io); pa_assert(data); pa_assert(l); pa_assert(io->ifd >= 0); pa_assert(ancil_data); if (io->ifd_type > 0) { ancil_data->creds_valid = false; ancil_data->nfd = 0; return pa_iochannel_read(io, data, l); } iov.iov_base = data; iov.iov_len = l; pa_zero(mh); mh.msg_iov = &iov; mh.msg_iovlen = 1; mh.msg_control = &cmsg; mh.msg_controllen = sizeof(cmsg); if ((r = recvmsg(io->ifd, &mh, 0)) >= 0) { struct cmsghdr *cmh; ancil_data->creds_valid = false; ancil_data->nfd = 0; for (cmh = CMSG_FIRSTHDR(&mh); cmh; cmh = CMSG_NXTHDR(&mh, cmh)) { if (cmh->cmsg_level != SOL_SOCKET) continue; if (cmh->cmsg_type == SCM_CREDENTIALS) { struct ucred u; pa_assert(cmh->cmsg_len == CMSG_LEN(sizeof(struct ucred))); memcpy(&u, CMSG_DATA(cmh), sizeof(struct ucred)); ancil_data->creds.gid = u.gid; ancil_data->creds.uid = u.uid; ancil_data->creds_valid = true; } else if (cmh->cmsg_type == SCM_RIGHTS) { int nfd = (cmh->cmsg_len - CMSG_LEN(0)) / sizeof(int); if (nfd > MAX_ANCIL_DATA_FDS) { int i; pa_log("Trying to receive too many file descriptors!"); for (i = 0; i < nfd; i++) pa_close(((int*) CMSG_DATA(cmh))[i]); continue; } memcpy(ancil_data->fds, CMSG_DATA(cmh), nfd * sizeof(int)); ancil_data->nfd = nfd; ancil_data->close_fds_on_cleanup = true; } } io->readable = io->hungup = false; enable_events(io); } if (r == -1 && errno == ENOTSOCK) { io->ifd_type = 1; return pa_iochannel_read_with_ancil_data(io, data, l, ancil_data); } return r; }
int mm_receive_fd(int sock) { struct msghdr msg; union { struct cmsghdr hdr; char buf[1024]; } cmsgbuf; struct cmsghdr *cmsg; struct iovec vec; ssize_t n; char ch; int fd; struct pollfd pfd; if (sizeof(cmsgbuf.buf) < CMSG_SPACE(sizeof(int))) { error("%s: %zu < %zu, recompile", __func__, sizeof(cmsgbuf.buf), CMSG_SPACE(sizeof(int))); return -1; } memset(&msg, 0, sizeof(msg)); memset(&cmsgbuf, 0, sizeof(cmsgbuf)); vec.iov_base = &ch; vec.iov_len = 1; msg.msg_iov = &vec; msg.msg_iovlen = 1; msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = CMSG_SPACE(sizeof(int)); pfd.fd = sock; pfd.events = POLLIN; while ((n = recvmsg(sock, &msg, 0)) == -1 && (errno == EAGAIN || errno == EINTR)) { debug3("%s: recvmsg: %s", __func__, strerror(errno)); (void)poll(&pfd, 1, -1); } if (n == -1) { error("%s: recvmsg: %s", __func__, strerror(errno)); return -1; } if (n != 1) { error("%s: recvmsg: expected received 1 got %ld", __func__, (long)n); return -1; } cmsg = CMSG_FIRSTHDR(&msg); if (cmsg == NULL) { error("%s: no message header", __func__); return -1; } if (cmsg->cmsg_type != SCM_RIGHTS) { error("%s: expected type %d got %d", __func__, SCM_RIGHTS, cmsg->cmsg_type); return -1; } fd = (*(int *)CMSG_DATA(cmsg)); return fd; }
ssize_t recvfromto(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen, struct sockaddr *to, socklen_t *tolen) { struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; struct in6_pktinfo *pkt6; struct sockaddr_in *in; struct sockaddr_in6 *in6; ssize_t ret; union { struct cmsghdr hdr; char buf[CMSG_SPACE(sizeof(struct sockaddr_storage))]; } cmsgbuf; #if !defined(IP_RECVDSTADDR) && defined(IP_PKTINFO) struct in_pktinfo *pkt; #endif bzero(&msg, sizeof(msg)); bzero(&cmsgbuf.buf, sizeof(cmsgbuf.buf)); iov.iov_base = buf; iov.iov_len = len; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = from; msg.msg_namelen = *fromlen; msg.msg_control = &cmsgbuf.buf; msg.msg_controllen = sizeof(cmsgbuf.buf); if ((ret = recvmsg(s, &msg, 0)) == -1) return (-1); *fromlen = SA_LEN(from); *tolen = 0; if (getsockname(s, to, tolen) != 0) *tolen = 0; for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { switch (from->sa_family) { case AF_INET: #if defined(IP_RECVDSTADDR) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_RECVDSTADDR) { in = (struct sockaddr_in *)to; in->sin_family = AF_INET; in->sin_len = *tolen = sizeof(*in); memcpy(&in->sin_addr, CMSG_DATA(cmsg), sizeof(struct in_addr)); } #elif defined(IP_PKTINFO) if (cmsg->cmsg_level == IPPROTO_IP && cmsg->cmsg_type == IP_PKTINFO) { in = (struct sockaddr_in *)to; in->sin_family = AF_INET; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN in->sin_len = *tolen = sizeof(*in); #else *tolen = sizeof(*in); #endif pkt = (struct in_pktinfo *)CMSG_DATA(cmsg); memcpy(&in->sin_addr, &pkt->ipi_addr, sizeof(struct in_addr)); } #endif break; case AF_INET6: if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_PKTINFO) { in6 = (struct sockaddr_in6 *)to; in6->sin6_family = AF_INET6; #ifdef HAVE_STRUCT_SOCKADDR_IN6_SIN6_LEN in6->sin6_len = *tolen = sizeof(*in6); #else *tolen = sizeof(*in6); #endif pkt6 = (struct in6_pktinfo *)CMSG_DATA(cmsg); memcpy(&in6->sin6_addr, &pkt6->ipi6_addr, sizeof(struct in6_addr)); if (IN6_IS_ADDR_LINKLOCAL(&in6->sin6_addr)) in6->sin6_scope_id = pkt6->ipi6_ifindex; } break; } } return (ret); }
int netl_listen(struct netl_handle *h, void *args) { int len, buflen, err; ssize_t status; struct nlmsghdr *hdr; struct sockaddr_nl nladdr; struct iovec iov; struct msghdr msg = { .msg_name = &nladdr, .msg_namelen = sizeof(nladdr), .msg_iov = &iov, .msg_iovlen = 1, }; char buf[8192]; struct pollfd fds[1]; if (h == NULL) return -1; iov.iov_base = buf; if (h->cb.init != NULL) { err = h->cb.init(args); if (err != 0) return err; } fds[0].events = POLLIN; fds[0].fd = h->fd; while (h->closing != 1) { int res = poll(fds, 1, NETL_POLL_TIMEOUT); if (res < 0 && errno != EINTR) { perror("error during cmdline_run poll"); return 0; } if (fds[0].revents & POLLIN) { iov.iov_len = sizeof(buf); status = recvmsg(h->fd, &msg, 0); if (status < 0) { // TODO: EINT / EAGAIN / ENOBUF should continue return -1; } if (status == 0) { // EOF return -1; } if (msg.msg_namelen != sizeof(nladdr)) { // Invalid length return -1; } for (hdr = (struct nlmsghdr *) buf; (size_t) status >= sizeof(*hdr);) { len = hdr->nlmsg_len; buflen = len - sizeof(*hdr); if (buflen < 0 || buflen > status) { // truncated return -1; } err = netl_handler(h, &nladdr, hdr, args); if (err < 0) return err; status -= NLMSG_ALIGN(len); hdr = (struct nlmsghdr *) ((char *) hdr + NLMSG_ALIGN(len)); } if (status) { // content not read return -1; } } } return 1; } static inline __u32 nl_mgrp(__u32 group) { return group ? (1 << (group - 1)) : 0; } struct netl_handle *netl_create(void) { struct netl_handle *netl_handle; int rcvbuf = 1024 * 1024 * 1024; socklen_t addr_len; unsigned subscriptions = 0; // get notified whenever interface change (new vlans / ...) subscriptions |= nl_mgrp(RTNLGRP_LINK); // get notified whenever ip changes subscriptions |= nl_mgrp(RTNLGRP_IPV4_IFADDR); subscriptions |= nl_mgrp(RTNLGRP_IPV6_IFADDR); // get notified on new routes subscriptions |= nl_mgrp(RTNLGRP_IPV4_ROUTE); subscriptions |= nl_mgrp(RTNLGRP_IPV6_ROUTE); // subscriptions |= RTNLGRP_IPV6_PREFIX; // prefix is for ipv6 RA // get notified by arp or ipv6 nd subscriptions |= nl_mgrp(RTNLGRP_NEIGH); // called whenever an iface is added/removed // subscriptions |= RTNLGRP_IPV4_NETCONF; // subscriptions |= RTNLGRP_IPV6_NETCONF; netl_handle = pktj_calloc("netl_handle", 1, sizeof(struct netl_handle), 0, SOCKET_ID_ANY); if (netl_handle == NULL) return NULL; netl_handle->fd = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE); if (netl_handle->fd < 0) { perror("Cannot open netlink socket"); goto free_netl_handle; } if (setsockopt (netl_handle->fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(rcvbuf)) < 0) { perror("Cannot set RCVBUF"); goto free_netl_handle; } memset(&netl_handle->local, 0, sizeof(netl_handle->local)); netl_handle->local.nl_family = AF_NETLINK; netl_handle->local.nl_groups = subscriptions; netl_handle->cb.neighbor4 = NULL; netl_handle->cb.route4 = NULL; if (bind (netl_handle->fd, (struct sockaddr *) &(netl_handle->local), sizeof(netl_handle->local)) < 0) { perror("Cannot bind netlink socket"); goto free_netl_handle; } addr_len = sizeof(netl_handle->local); if (getsockname (netl_handle->fd, (struct sockaddr *) &netl_handle->local, &addr_len) < 0) { perror("Cannot getsockname"); goto free_netl_handle; } if (addr_len != sizeof(netl_handle->local)) { perror("Wrong address length"); goto free_netl_handle; } if (netl_handle->local.nl_family != AF_NETLINK) { perror("Wrong address family"); goto free_netl_handle; } netl_handle->closing = 0; return netl_handle; free_netl_handle: pktj_free(netl_handle); return NULL; } int netl_free(struct netl_handle *h) { if (h != NULL) { if (h->fd > 0) { close(h->fd); h->fd = -1; } pktj_free(h); } return 0; }
/* * Dispatch kernel routing socket messages. */ static int rtm_dispatch(void) { struct msghdr mh; struct iovec iov[1]; struct rt_msghdr *rtm; struct rtm_dispinfo *di; ssize_t len; int retval; di = malloc(sizeof(*di)); if (di == NULL) { daemon_log(LOG_ERR, "malloc(%d): %s", sizeof(*di), strerror(errno)); return (-1); } di->di_buflen = MAX_RTMSG_SIZE; di->di_buf = calloc(MAX_RTMSG_SIZE, 1); if (di->di_buf == NULL) { free(di); daemon_log(LOG_ERR, "calloc(%d): %s", MAX_RTMSG_SIZE, strerror(errno)); return (-1); } memset(&mh, 0, sizeof(mh)); iov[0].iov_base = di->di_buf; iov[0].iov_len = di->di_buflen; mh.msg_iov = iov; mh.msg_iovlen = 1; retval = 0; for (;;) { len = recvmsg(fd, &mh, MSG_DONTWAIT); if (len == -1) { if (errno == EWOULDBLOCK) break; else { daemon_log(LOG_ERR, "recvmsg(): %s", strerror(errno)); retval = -1; break; } } rtm = (void *)di->di_buf; if (rtm->rtm_version != RTM_VERSION) { daemon_log(LOG_ERR, "unknown routing socket message (version %d)\n", rtm->rtm_version); /* this is non-fatal; just ignore it for now. */ continue; } switch (rtm->rtm_type) { case RTM_NEWADDR: case RTM_DELADDR: retval = rtm_dispatch_newdeladdr(di); break; case RTM_IFANNOUNCE: retval = rtm_dispatch_ifannounce(di); break; default: daemon_log(LOG_DEBUG, "%s: rtm_type %d ignored", __func__, rtm->rtm_type); break; } /* * If we got an error; assume our position on the call * stack is enclosed by a level-triggered event loop, * and signal the error condition. */ if (retval != 0) break; } free(di->di_buf); free(di); return (retval); }
void loop_udp(int sockfd) { int maxfdp1, nread, ntowrite, stdineof, clilen, servlen, flags; fd_set rset; struct sockaddr_in cliaddr; /* for UDP server */ struct sockaddr_in servaddr; /* for UDP client */ #ifdef HAVE_MSGHDR_MSG_CONTROL struct iovec iov[1]; struct msghdr msg; #ifdef IP_RECVDSTADDR /* 4.3BSD Reno and later */ static struct cmsghdr *cmptr = NULL; /* malloc'ed */ struct in_addr dstinaddr; /* for UDP server */ #define CONTROLLEN (sizeof(struct cmsghdr) + sizeof(struct in_addr)) #endif /* IP_RECVDSTADDR */ #endif /* MSG_TRUNC */ if (pauseinit) sleep_us(pauseinit*1000); /* intended for server */ flags = 0; stdineof = 0; FD_ZERO(&rset); maxfdp1 = sockfd + 1; /* check descriptors [0..sockfd] */ /* If UDP client issues connect(), recv() and write() are used. Server is harder since cannot issue connect(). We use recvfrom() or recvmsg(), depending on OS. */ for ( ; ; ) { if (stdineof == 0) FD_SET(STDIN_FILENO, &rset); FD_SET(sockfd, &rset); if (select(maxfdp1, &rset, NULL, NULL, NULL) < 0) err_sys("select error"); if (FD_ISSET(STDIN_FILENO, &rset)) { /* data to read on stdin */ if ( (nread = read(STDIN_FILENO, rbuf, readlen)) < 0) err_sys("read error from stdin"); else if (nread == 0) { /* EOF on stdin */ if (halfclose) { if (shutdown(sockfd, SHUT_WR) < 0) err_sys("shutdown() error"); FD_CLR(STDIN_FILENO, &rset); stdineof = 1; /* don't read stdin anymore */ continue; /* back to select() */ } break; /* default: stdin EOF -> done */ } if (crlf) { ntowrite = crlf_add(wbuf, writelen, rbuf, nread); if (connectudp) { if (write(sockfd, wbuf, ntowrite) != ntowrite) err_sys("write error"); } else { if (sendto(sockfd, wbuf, ntowrite, 0, (struct sockaddr *) &servaddr, sizeof(servaddr)) != ntowrite) err_sys("sendto error"); } } else { if (connectudp) { if (write(sockfd, rbuf, nread) != nread) err_sys("write error"); } else { if (sendto(sockfd, rbuf, nread, 0, (struct sockaddr *) &servaddr, sizeof(servaddr)) != nread) err_sys("sendto error"); } } } if (FD_ISSET(sockfd, &rset)) { /* data to read from socket */ if (server) { clilen = sizeof(cliaddr); #ifndef MSG_TRUNC /* vanilla BSD sockets */ nread = recvfrom(sockfd, rbuf, readlen, 0, (struct sockaddr *) &cliaddr, &clilen); #else /* 4.3BSD Reno and later; use recvmsg() to get at MSG_TRUNC flag */ /* Also lets us get at control information (destination address) */ iov[0].iov_base = rbuf; iov[0].iov_len = readlen; msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_name = (caddr_t) &cliaddr; msg.msg_namelen = clilen; #ifdef IP_RECVDSTADDR if (cmptr == NULL && (cmptr = malloc(CONTROLLEN)) == NULL) err_sys("malloc error for control buffer"); msg.msg_control = (caddr_t) cmptr; /* for dest address */ msg.msg_controllen = CONTROLLEN; #else msg.msg_control = (caddr_t) 0; /* no ancillary data */ msg.msg_controllen = 0; #endif /* IP_RECVDSTADDR */ msg.msg_flags = 0; /* flags returned here */ nread = recvmsg(sockfd, &msg, 0); #endif /* HAVE_MSGHDR_MSG_CONTROL */ if (nread < 0) err_sys("datagram receive error"); if (verbose) { printf("from %s", INET_NTOA(cliaddr.sin_addr)); #ifdef HAVE_MSGHDR_MSG_CONTROL #ifdef IP_RECVDSTADDR if (recvdstaddr) { if (cmptr->cmsg_len != CONTROLLEN) err_quit("control length (%d) != %d", cmptr->cmsg_len, CONTROLLEN); if (cmptr->cmsg_level != IPPROTO_IP) err_quit("control level != IPPROTO_IP"); if (cmptr->cmsg_type != IP_RECVDSTADDR) err_quit("control type != IP_RECVDSTADDR"); bcopy(CMSG_DATA(cmptr), &dstinaddr, sizeof(struct in_addr)); bzero(cmptr, CONTROLLEN); printf(", to %s", INET_NTOA(dstinaddr)); } #endif /* IP_RECVDSTADDR */ #endif /* HAVE_MSGHDR_MSG_CONTROL */ printf(": "); fflush(stdout); } #ifdef MSG_TRUNC if (msg.msg_flags & MSG_TRUNC) printf("(datagram truncated)\n"); #endif } else if (connectudp) { /* msgpeek = 0 or MSG_PEEK */ flags = msgpeek; oncemore: if ( (nread = recv(sockfd, rbuf, readlen, flags)) < 0) err_sys("recv error"); else if (nread == 0) { if (verbose) fprintf(stderr, "connection closed by peer\n"); break; /* EOF, terminate */ } } else { /* Must use recvfrom() for unconnected UDP client */ servlen = sizeof(servaddr); nread = recvfrom(sockfd, rbuf, readlen, 0, (struct sockaddr *) &servaddr, &servlen); if (nread < 0) err_sys("datagram recvfrom() error"); if (verbose) { printf("from %s", INET_NTOA(servaddr.sin_addr)); printf(": "); fflush(stdout); } } if (crlf) { ntowrite = crlf_strip(wbuf, writelen, rbuf, nread); if (writen(STDOUT_FILENO, wbuf, ntowrite) != ntowrite) err_sys("writen error to stdout"); } else { if (writen(STDOUT_FILENO, rbuf, nread) != nread) err_sys("writen error to stdout"); } if (flags != 0) { flags = 0; /* no infinite loop */ goto oncemore; /* read the message again */ } } } if (pauseclose) { if (verbose) fprintf(stderr, "pausing before close\n"); sleep_us(pauseclose*1000); } if (close(sockfd) < 0) err_sys("close error"); /* since SO_LINGER may be set */ }
static int manager_receive_response(sd_event_source *source, int fd, uint32_t revents, void *userdata) { Manager *m = userdata; struct ntp_msg ntpmsg; struct iovec iov = { .iov_base = &ntpmsg, .iov_len = sizeof(ntpmsg), }; union { struct cmsghdr cmsghdr; uint8_t buf[CMSG_SPACE(sizeof(struct timeval))]; } control; union sockaddr_union server_addr; struct msghdr msghdr = { .msg_iov = &iov, .msg_iovlen = 1, .msg_control = &control, .msg_controllen = sizeof(control), .msg_name = &server_addr, .msg_namelen = sizeof(server_addr), }; struct cmsghdr *cmsg; struct timespec now_ts; struct timeval *recv_time; ssize_t len; double origin, receive, trans, dest; double delay, offset; bool spike; int leap_sec; int r; assert(source); assert(m); if (revents & (EPOLLHUP|EPOLLERR)) { log_warning("Server connection returned error."); return manager_connect(m); } len = recvmsg(fd, &msghdr, MSG_DONTWAIT); if (len < 0) { if (errno == EAGAIN) return 0; log_warning("Error receiving message. Disconnecting."); return manager_connect(m); } if (iov.iov_len < sizeof(struct ntp_msg)) { log_warning("Invalid response from server. Disconnecting."); return manager_connect(m); } if (!m->current_server_name || !m->current_server_address || !sockaddr_equal(&server_addr, &m->current_server_address->sockaddr)) { log_debug("Response from unknown server."); return 0; } recv_time = NULL; for (cmsg = CMSG_FIRSTHDR(&msghdr); cmsg; cmsg = CMSG_NXTHDR(&msghdr, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET) continue; switch (cmsg->cmsg_type) { case SCM_TIMESTAMP: recv_time = (struct timeval *) CMSG_DATA(cmsg); break; } } if (!recv_time) { log_error("Invalid packet timestamp."); return -EINVAL; } if (!m->pending) { log_debug("Unexpected reply. Ignoring."); return 0; } /* check our "time cookie" (we just stored nanoseconds in the fraction field) */ if (be32toh(ntpmsg.origin_time.sec) != m->trans_time.tv_sec + OFFSET_1900_1970 || be32toh(ntpmsg.origin_time.frac) != m->trans_time.tv_nsec) { log_debug("Invalid reply; not our transmit time. Ignoring."); return 0; } m->event_timeout = sd_event_source_unref(m->event_timeout); if (be32toh(ntpmsg.recv_time.sec) < TIME_EPOCH + OFFSET_1900_1970 || be32toh(ntpmsg.trans_time.sec) < TIME_EPOCH + OFFSET_1900_1970) { log_debug("Invalid reply, returned times before epoch. Ignoring."); return manager_connect(m); } if (NTP_FIELD_LEAP(ntpmsg.field) == NTP_LEAP_NOTINSYNC) { log_debug("Server is not synchronized. Disconnecting."); return manager_connect(m); } if (!IN_SET(NTP_FIELD_VERSION(ntpmsg.field), 3, 4)) { log_debug("Response NTPv%d. Disconnecting.", NTP_FIELD_VERSION(ntpmsg.field)); return manager_connect(m); } if (NTP_FIELD_MODE(ntpmsg.field) != NTP_MODE_SERVER) { log_debug("Unsupported mode %d. Disconnecting.", NTP_FIELD_MODE(ntpmsg.field)); return manager_connect(m); } /* valid packet */ m->pending = false; m->retry_interval = 0; /* announce leap seconds */ if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_PLUSSEC) leap_sec = 1; else if (NTP_FIELD_LEAP(ntpmsg.field) & NTP_LEAP_MINUSSEC) leap_sec = -1; else leap_sec = 0; /* * "Timestamp Name ID When Generated * ------------------------------------------------------------ * Originate Timestamp T1 time request sent by client * Receive Timestamp T2 time request received by server * Transmit Timestamp T3 time reply sent by server * Destination Timestamp T4 time reply received by client * * The round-trip delay, d, and system clock offset, t, are defined as: * d = (T4 - T1) - (T3 - T2) t = ((T2 - T1) + (T3 - T4)) / 2" */ assert_se(clock_gettime(clock_boottime_or_monotonic(), &now_ts) >= 0); origin = tv_to_d(recv_time) - (ts_to_d(&now_ts) - ts_to_d(&m->trans_time_mon)) + OFFSET_1900_1970; receive = ntp_ts_to_d(&ntpmsg.recv_time); trans = ntp_ts_to_d(&ntpmsg.trans_time); dest = tv_to_d(recv_time) + OFFSET_1900_1970; offset = ((receive - origin) + (trans - dest)) / 2; delay = (dest - origin) - (trans - receive); spike = manager_sample_spike_detection(m, offset, delay); manager_adjust_poll(m, offset, spike); log_debug("NTP response:\n" " leap : %u\n" " version : %u\n" " mode : %u\n" " stratum : %u\n" " precision : %.6f sec (%d)\n" " reference : %.4s\n" " origin : %.3f\n" " receive : %.3f\n" " transmit : %.3f\n" " dest : %.3f\n" " offset : %+.3f sec\n" " delay : %+.3f sec\n" " packet count : %"PRIu64"\n" " jitter : %.3f%s\n" " poll interval: " USEC_FMT "\n", NTP_FIELD_LEAP(ntpmsg.field), NTP_FIELD_VERSION(ntpmsg.field), NTP_FIELD_MODE(ntpmsg.field), ntpmsg.stratum, exp2(ntpmsg.precision), ntpmsg.precision, ntpmsg.stratum == 1 ? ntpmsg.refid : "n/a", origin - OFFSET_1900_1970, receive - OFFSET_1900_1970, trans - OFFSET_1900_1970, dest - OFFSET_1900_1970, offset, delay, m->packet_count, m->samples_jitter, spike ? " spike" : "", m->poll_interval_usec / USEC_PER_SEC); if (!spike) { m->sync = true; r = manager_adjust_clock(m, offset, leap_sec); if (r < 0) log_error("Failed to call clock_adjtime(): %m"); } log_info("interval/delta/delay/jitter/drift " USEC_FMT "s/%+.3fs/%.3fs/%.3fs/%+ippm%s", m->poll_interval_usec / USEC_PER_SEC, offset, delay, m->samples_jitter, m->drift_ppm, spike ? " (ignored)" : ""); r = manager_arm_timer(m, m->poll_interval_usec); if (r < 0) { log_error("Failed to rearm timer: %s", strerror(-r)); return r; } return 0; } static int manager_listen_setup(Manager *m) { union sockaddr_union addr = {}; static const int tos = IPTOS_LOWDELAY; static const int on = 1; int r; assert(m); assert(m->server_socket < 0); assert(!m->event_receive); assert(m->current_server_address); addr.sa.sa_family = m->current_server_address->sockaddr.sa.sa_family; m->server_socket = socket(addr.sa.sa_family, SOCK_DGRAM | SOCK_CLOEXEC, 0); if (m->server_socket < 0) return -errno; r = bind(m->server_socket, &addr.sa, m->current_server_address->socklen); if (r < 0) return -errno; r = setsockopt(m->server_socket, SOL_SOCKET, SO_TIMESTAMP, &on, sizeof(on)); if (r < 0) return -errno; setsockopt(m->server_socket, IPPROTO_IP, IP_TOS, &tos, sizeof(tos)); return sd_event_add_io(m->event, &m->event_receive, m->server_socket, EPOLLIN, manager_receive_response, m); } static int manager_begin(Manager *m) { _cleanup_free_ char *pretty = NULL; int r; assert(m); assert_return(m->current_server_name, -EHOSTUNREACH); assert_return(m->current_server_address, -EHOSTUNREACH); m->poll_interval_usec = NTP_POLL_INTERVAL_MIN_SEC * USEC_PER_SEC; server_address_pretty(m->current_server_address, &pretty); log_info("Using NTP server %s (%s).", strna(pretty), m->current_server_name->string); sd_notifyf(false, "STATUS=Using Time Server %s (%s).", strna(pretty), m->current_server_name->string); r = manager_listen_setup(m); if (r < 0) { log_warning("Failed to setup connection socket: %s", strerror(-r)); return r; } r = manager_clock_watch_setup(m); if (r < 0) return r; return manager_send_request(m); } void manager_set_server_name(Manager *m, ServerName *n) { assert(m); if (m->current_server_name == n) return; m->current_server_name = n; m->current_server_address = NULL; manager_disconnect(m); if (n) log_debug("Selected server %s.", n->string); }
int recverr(int fd, int ttl) { int res; struct probehdr rcvbuf; char cbuf[512]; struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; struct sock_extended_err *e; struct sockaddr_in addr; struct timeval tv; struct timeval *rettv; int slot; int rethops; int sndhops; int progress = -1; int broken_router; restart: memset(&rcvbuf, -1, sizeof(rcvbuf)); iov.iov_base = &rcvbuf; iov.iov_len = sizeof(rcvbuf); msg.msg_name = (__u8*)&addr; msg.msg_namelen = sizeof(addr); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_flags = 0; msg.msg_control = cbuf; msg.msg_controllen = sizeof(cbuf); gettimeofday(&tv, NULL); res = recvmsg(fd, &msg, MSG_ERRQUEUE); if (res < 0) { if (errno == EAGAIN) return progress; goto restart; } progress = mtu; rethops = -1; sndhops = -1; e = NULL; rettv = NULL; slot = ntohs(addr.sin_port) - base_port; if (slot>=0 && slot < 63 && his[slot].hops) { sndhops = his[slot].hops; rettv = &his[slot].sendtime; his[slot].hops = 0; } broken_router = 0; if (res == sizeof(rcvbuf)) { if (rcvbuf.ttl == 0 || rcvbuf.tv.tv_sec == 0) { broken_router = 1; } else { sndhops = rcvbuf.ttl; rettv = &rcvbuf.tv; } } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level == SOL_IP) { if (cmsg->cmsg_type == IP_RECVERR) { e = (struct sock_extended_err *) CMSG_DATA(cmsg); } else if (cmsg->cmsg_type == IP_TTL) { rethops = *(int*)CMSG_DATA(cmsg); } else { printf("cmsg:%d\n ", cmsg->cmsg_type); } } } if (e == NULL) { printf("no info\n"); return 0; } if (e->ee_origin == SO_EE_ORIGIN_LOCAL) { printf("%2d?: %-15s ", ttl, "[LOCALHOST]"); } else if (e->ee_origin == SO_EE_ORIGIN_ICMP) { char abuf[128]; struct sockaddr_in *sin = (struct sockaddr_in*)(e+1); inet_ntop(AF_INET, &sin->sin_addr, abuf, sizeof(abuf)); if (sndhops>0) printf("%2d: ", sndhops); else printf("%2d?: ", ttl); if(!no_resolve) { char fabuf[256]; struct hostent *h; fflush(stdout); h = gethostbyaddr((char *) &sin->sin_addr, sizeof(sin->sin_addr), AF_INET); snprintf(fabuf, sizeof(fabuf), "%s (%s)", h ? h->h_name : abuf, abuf); printf("%-52s ", fabuf); } else { printf("%-15s ", abuf); } } if (rethops>=0) { if (rethops<=64) rethops = 65-rethops; else if (rethops<=128) rethops = 129-rethops; else rethops = 256-rethops; if (sndhops>=0 && rethops != sndhops) printf("asymm %2d ", rethops); else if (sndhops<0 && rethops != ttl) printf("asymm %2d ", rethops); } if (rettv) { int diff = (tv.tv_sec-rettv->tv_sec)*1000000+(tv.tv_usec-rettv->tv_usec); printf("%3d.%03dms ", diff/1000, diff%1000); if (broken_router) printf("(This broken router returned corrupted payload) "); } switch (e->ee_errno) { case ETIMEDOUT: printf("\n"); break; case EMSGSIZE: printf("pmtu %d\n", e->ee_info); mtu = e->ee_info; progress = mtu; break; case ECONNREFUSED: printf("reached\n"); hops_to = sndhops<0 ? ttl : sndhops; hops_from = rethops; return 0; case EPROTO: printf("!P\n"); return 0; case EHOSTUNREACH: if (e->ee_origin == SO_EE_ORIGIN_ICMP && e->ee_type == 11 && e->ee_code == 0) { printf("\n"); break; } printf("!H\n"); return 0; case ENETUNREACH: printf("!N\n"); return 0; case EACCES: printf("!A\n"); return 0; default: printf("\n"); errno = e->ee_errno; perror("NET ERROR"); return 0; } goto restart; }
int main(int argc, char **argv) { fd_set rdfs; int s[MAXSOCK]; int bridge = 0; useconds_t bridge_delay = 0; unsigned char timestamp = 0; unsigned char dropmonitor = 0; unsigned char extra_msg_info = 0; unsigned char silent = SILENT_INI; unsigned char silentani = 0; unsigned char color = 0; unsigned char view = 0; unsigned char log = 0; unsigned char logfrmt = 0; int count = 0; int rcvbuf_size = 0; int opt, ret; int currmax, numfilter; char *ptr, *nptr; struct sockaddr_can addr; char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))]; struct iovec iov; struct msghdr msg; struct cmsghdr *cmsg; struct can_filter *rfilter; can_err_mask_t err_mask; struct canfd_frame frame; int nbytes, i, maxdlen; struct ifreq ifr; struct timeval tv, last_tv; FILE *logfile = NULL; signal(SIGTERM, sigterm); signal(SIGHUP, sigterm); signal(SIGINT, sigterm); last_tv.tv_sec = 0; last_tv.tv_usec = 0; while ((opt = getopt(argc, argv, "t:ciaSs:b:B:u:ldxLn:r:he?")) != -1) { switch (opt) { case 't': timestamp = optarg[0]; if ((timestamp != 'a') && (timestamp != 'A') && (timestamp != 'd') && (timestamp != 'z')) { fprintf(stderr, "%s: unknown timestamp mode '%c' - ignored\n", basename(argv[0]), optarg[0]); timestamp = 0; } break; case 'c': color++; break; case 'i': view |= CANLIB_VIEW_BINARY; break; case 'a': view |= CANLIB_VIEW_ASCII; break; case 'S': view |= CANLIB_VIEW_SWAP; break; case 'e': view |= CANLIB_VIEW_ERROR; break; case 's': silent = atoi(optarg); if (silent > SILENT_ON) { print_usage(basename(argv[0])); exit(1); } break; case 'b': case 'B': if (strlen(optarg) >= IFNAMSIZ) { fprintf(stderr, "Name of CAN device '%s' is too long!\n\n", optarg); return 1; } else { bridge = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (bridge < 0) { perror("bridge socket"); return 1; } addr.can_family = AF_CAN; strcpy(ifr.ifr_name, optarg); if (ioctl(bridge, SIOCGIFINDEX, &ifr) < 0) perror("SIOCGIFINDEX"); addr.can_ifindex = ifr.ifr_ifindex; if (!addr.can_ifindex) { perror("invalid bridge interface"); return 1; } /* disable default receive filter on this write-only RAW socket */ setsockopt(bridge, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); if (opt == 'B') { const int loopback = 0; setsockopt(bridge, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback)); } if (bind(bridge, (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bridge bind"); return 1; } } break; case 'u': bridge_delay = (useconds_t)strtoul(optarg, (char **)NULL, 10); break; case 'l': log = 1; break; case 'd': dropmonitor = 1; break; case 'x': extra_msg_info = 1; break; case 'L': logfrmt = 1; break; case 'n': count = atoi(optarg); if (count < 1) { print_usage(basename(argv[0])); exit(1); } break; case 'r': rcvbuf_size = atoi(optarg); if (rcvbuf_size < 1) { print_usage(basename(argv[0])); exit(1); } break; default: print_usage(basename(argv[0])); exit(1); break; } } if (optind == argc) { print_usage(basename(argv[0])); exit(0); } if (logfrmt && view) { fprintf(stderr, "Log file format selected: Please disable ASCII/BINARY/SWAP options!\n"); exit(0); } if (silent == SILENT_INI) { if (log) { fprintf(stderr, "Disabled standard output while logging.\n"); silent = SILENT_ON; /* disable output on stdout */ } else silent = SILENT_OFF; /* default output */ } currmax = argc - optind; /* find real number of CAN devices */ if (currmax > MAXSOCK) { fprintf(stderr, "More than %d CAN devices given on commandline!\n", MAXSOCK); return 1; } for (i=0; i < currmax; i++) { ptr = argv[optind+i]; nptr = strchr(ptr, ','); #ifdef DEBUG printf("open %d '%s'.\n", i, ptr); #endif s[i] = socket(PF_CAN, SOCK_RAW, CAN_RAW); if (s[i] < 0) { perror("socket"); return 1; } cmdlinename[i] = ptr; /* save pointer to cmdline name of this socket */ if (nptr) nbytes = nptr - ptr; /* interface name is up the first ',' */ else nbytes = strlen(ptr); /* no ',' found => no filter definitions */ if (nbytes >= IFNAMSIZ) { fprintf(stderr, "name of CAN device '%s' is too long!\n", ptr); return 1; } if (nbytes > max_devname_len) max_devname_len = nbytes; /* for nice printing */ addr.can_family = AF_CAN; memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name)); strncpy(ifr.ifr_name, ptr, nbytes); #ifdef DEBUG printf("using interface name '%s'.\n", ifr.ifr_name); #endif if (strcmp(ANYDEV, ifr.ifr_name)) { if (ioctl(s[i], SIOCGIFINDEX, &ifr) < 0) { perror("SIOCGIFINDEX"); exit(1); } addr.can_ifindex = ifr.ifr_ifindex; } else addr.can_ifindex = 0; /* any can interface */ if (nptr) { /* found a ',' after the interface name => check for filters */ /* determine number of filters to alloc the filter space */ numfilter = 0; ptr = nptr; while (ptr) { numfilter++; ptr++; /* hop behind the ',' */ ptr = strchr(ptr, ','); /* exit condition */ } rfilter = malloc(sizeof(struct can_filter) * numfilter); if (!rfilter) { fprintf(stderr, "Failed to create filter space!\n"); return 1; } numfilter = 0; err_mask = 0; while (nptr) { ptr = nptr+1; /* hop behind the ',' */ nptr = strchr(ptr, ','); /* update exit condition */ if (sscanf(ptr, "%x:%x", &rfilter[numfilter].can_id, &rfilter[numfilter].can_mask) == 2) { rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG; numfilter++; } else if (sscanf(ptr, "%x~%x", &rfilter[numfilter].can_id, &rfilter[numfilter].can_mask) == 2) { rfilter[numfilter].can_id |= CAN_INV_FILTER; rfilter[numfilter].can_mask &= ~CAN_ERR_FLAG; numfilter++; } else if (sscanf(ptr, "#%x", &err_mask) != 1) { fprintf(stderr, "Error in filter option parsing: '%s'\n", ptr); return 1; } } if (err_mask) setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask)); if (numfilter) setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FILTER, rfilter, numfilter * sizeof(struct can_filter)); free(rfilter); } /* if (nptr) */ /* try to switch the socket into CAN FD mode */ setsockopt(s[i], SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on)); if (rcvbuf_size) { int curr_rcvbuf_size; socklen_t curr_rcvbuf_size_len = sizeof(curr_rcvbuf_size); /* try SO_RCVBUFFORCE first, if we run with CAP_NET_ADMIN */ if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUFFORCE, &rcvbuf_size, sizeof(rcvbuf_size)) < 0) { #ifdef DEBUG printf("SO_RCVBUFFORCE failed so try SO_RCVBUF ...\n"); #endif if (setsockopt(s[i], SOL_SOCKET, SO_RCVBUF, &rcvbuf_size, sizeof(rcvbuf_size)) < 0) { perror("setsockopt SO_RCVBUF"); return 1; } if (getsockopt(s[i], SOL_SOCKET, SO_RCVBUF, &curr_rcvbuf_size, &curr_rcvbuf_size_len) < 0) { perror("getsockopt SO_RCVBUF"); return 1; } /* Only print a warning the first time we detect the adjustment */ /* n.b.: The wanted size is doubled in Linux in net/sore/sock.c */ if (!i && curr_rcvbuf_size < rcvbuf_size*2) fprintf(stderr, "The socket receive buffer size was " "adjusted due to /proc/sys/net/core/rmem_max.\n"); } } if (timestamp || log || logfrmt) { const int timestamp_on = 1; if (setsockopt(s[i], SOL_SOCKET, SO_TIMESTAMP, ×tamp_on, sizeof(timestamp_on)) < 0) { perror("setsockopt SO_TIMESTAMP"); return 1; } } if (dropmonitor) { const int dropmonitor_on = 1; if (setsockopt(s[i], SOL_SOCKET, SO_RXQ_OVFL, &dropmonitor_on, sizeof(dropmonitor_on)) < 0) { perror("setsockopt SO_RXQ_OVFL not supported by your Linux Kernel"); return 1; } } if (bind(s[i], (struct sockaddr *)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; } } if (log) { time_t currtime; struct tm now; char fname[sizeof("candump-2006-11-20_202026.log")+1]; if (time(&currtime) == (time_t)-1) { perror("time"); return 1; } localtime_r(&currtime, &now); sprintf(fname, "candump-%04d-%02d-%02d_%02d%02d%02d.log", now.tm_year + 1900, now.tm_mon + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec); if (silent != SILENT_ON) printf("\nWarning: console output active while logging!"); fprintf(stderr, "\nEnabling Logfile '%s'\n\n", fname); logfile = fopen(fname, "w"); if (!logfile) { perror("logfile"); return 1; } } /* these settings are static and can be held out of the hot path */ iov.iov_base = &frame; msg.msg_name = &addr; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = &ctrlmsg; while (running) { FD_ZERO(&rdfs); for (i=0; i<currmax; i++) FD_SET(s[i], &rdfs); if ((ret = select(s[currmax-1]+1, &rdfs, NULL, NULL, NULL)) < 0) { //perror("select"); running = 0; continue; } for (i=0; i<currmax; i++) { /* check all CAN RAW sockets */ if (FD_ISSET(s[i], &rdfs)) { int idx; /* these settings may be modified by recvmsg() */ iov.iov_len = sizeof(frame); msg.msg_namelen = sizeof(addr); msg.msg_controllen = sizeof(ctrlmsg); msg.msg_flags = 0; nbytes = recvmsg(s[i], &msg, 0); if (nbytes < 0) { perror("read"); return 1; } if ((size_t)nbytes == CAN_MTU) maxdlen = CAN_MAX_DLEN; else if ((size_t)nbytes == CANFD_MTU) maxdlen = CANFD_MAX_DLEN; else { fprintf(stderr, "read: incomplete CAN frame\n"); return 1; } if (count && (--count == 0)) running = 0; if (bridge) { if (bridge_delay) usleep(bridge_delay); nbytes = write(bridge, &frame, nbytes); if (nbytes < 0) { perror("bridge write"); return 1; } else if ((size_t)nbytes != CAN_MTU && (size_t)nbytes != CANFD_MTU) { fprintf(stderr,"bridge write: incomplete CAN frame\n"); return 1; } } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg && (cmsg->cmsg_level == SOL_SOCKET); cmsg = CMSG_NXTHDR(&msg,cmsg)) { if (cmsg->cmsg_type == SO_TIMESTAMP) tv = *(struct timeval *)CMSG_DATA(cmsg); else if (cmsg->cmsg_type == SO_RXQ_OVFL) dropcnt[i] = *(__u32 *)CMSG_DATA(cmsg); } /* check for (unlikely) dropped frames on this specific socket */ if (dropcnt[i] != last_dropcnt[i]) { __u32 frames; if (dropcnt[i] > last_dropcnt[i]) frames = dropcnt[i] - last_dropcnt[i]; else frames = 4294967295U - last_dropcnt[i] + dropcnt[i]; /* 4294967295U == UINT32_MAX */ if (silent != SILENT_ON) printf("DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n", frames, (frames > 1)?"s":"", cmdlinename[i], dropcnt[i]); if (log) fprintf(logfile, "DROPCOUNT: dropped %d CAN frame%s on '%s' socket (total drops %d)\n", frames, (frames > 1)?"s":"", cmdlinename[i], dropcnt[i]); last_dropcnt[i] = dropcnt[i]; } idx = idx2dindex(addr.can_ifindex, s[i]); /* once we detected a EFF frame indent SFF frames accordingly */ if (frame.can_id & CAN_EFF_FLAG) view |= CANLIB_VIEW_INDENT_SFF; if (log) { /* log CAN frame with absolute timestamp & device */ fprintf(logfile, "(%ld.%06ld) ", tv.tv_sec, tv.tv_usec); fprintf(logfile, "%*s ", max_devname_len, devname[idx]); /* without seperator as logfile use-case is parsing */ fprint_canframe(logfile, &frame, "\n", 0, maxdlen); } if (logfrmt) { /* print CAN frame in log file style to stdout */ printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec); printf("%*s ", max_devname_len, devname[idx]); fprint_canframe(stdout, &frame, "\n", 0, maxdlen); goto out_fflush; /* no other output to stdout */ } if (silent != SILENT_OFF){ if (silent == SILENT_ANI) { printf("%c\b", anichar[silentani%=MAXANI]); silentani++; } goto out_fflush; /* no other output to stdout */ } printf(" %s", (color>2)?col_on[idx%MAXCOL]:""); switch (timestamp) { case 'a': /* absolute with timestamp */ printf("(%ld.%06ld) ", tv.tv_sec, tv.tv_usec); break; case 'A': /* absolute with date */ { struct tm tm; char timestring[25]; tm = *localtime(&tv.tv_sec); strftime(timestring, 24, "%Y-%m-%d %H:%M:%S", &tm); printf("(%s.%06ld) ", timestring, tv.tv_usec); } break; case 'd': /* delta */ case 'z': /* starting with zero */ { struct timeval diff; if (last_tv.tv_sec == 0) /* first init */ last_tv = tv; diff.tv_sec = tv.tv_sec - last_tv.tv_sec; diff.tv_usec = tv.tv_usec - last_tv.tv_usec; if (diff.tv_usec < 0) diff.tv_sec--, diff.tv_usec += 1000000; if (diff.tv_sec < 0) diff.tv_sec = diff.tv_usec = 0; printf("(%03ld.%06ld) ", diff.tv_sec, diff.tv_usec); if (timestamp == 'd') last_tv = tv; /* update for delta calculation */ } break; default: /* no timestamp output */ break; } printf(" %s", (color && (color<3))?col_on[idx%MAXCOL]:""); printf("%*s", max_devname_len, devname[idx]); if (extra_msg_info) { if (msg.msg_flags & MSG_DONTROUTE) printf (" TX %s", extra_m_info[frame.flags & 3]); else printf (" RX %s", extra_m_info[frame.flags & 3]); } printf("%s ", (color==1)?col_off:""); fprint_long_canframe(stdout, &frame, NULL, view, maxdlen); printf("%s", (color>1)?col_off:""); printf("\n"); } out_fflush: fflush(stdout); } } for (i=0; i<currmax; i++) close(s[i]); if (bridge) close(bridge); if (log) fclose(logfile); return 0; }
/* See comment for "process_child" regarding reverse roles */ int process_parent( int sv[2] ) { /* Some of the run options mean that we terminate before our "child". We don't want to confuse * the child with SIGCHLD of which it is not aware. */ int grandchild_pid=fork(); if( grandchild_pid==-1 ) { perror("privbind: Error creating grandchild process"); return 1; } if( grandchild_pid!=0 ) { /* We are the grandchild's parent. Terminate cleanly to indicate to our parent that it's ok * to start the actual program. */ return 0; } /* Close the child socket */ close(sv[0]); /* wait for request from the child */ do { struct msghdr msghdr={0}; struct cmsghdr *cmsg; char buf[CMSG_SPACE(sizeof(int))]; struct ipc_msg_req request; struct iovec iov; struct ipc_msg_reply reply = {0}; int recvbytes; msghdr.msg_control=buf; msghdr.msg_controllen=sizeof(buf); iov.iov_base = &request; iov.iov_len = sizeof request; msghdr.msg_iov = &iov; msghdr.msg_iovlen = 1; if ( (recvbytes = recvmsg( sv[1], &msghdr, 0)) > 0) { if ((cmsg = (struct cmsghdr *)CMSG_FIRSTHDR(&msghdr)) != NULL) { switch (request.type) { case MSG_REQ_NONE: reply.type = MSG_REP_NONE; if (send(sv[1], &reply, sizeof reply, 0) != sizeof reply) perror("privbind: send"); break; case MSG_REQ_BIND: reply.type = MSG_REP_STAT; int sock; if (cmsg->cmsg_len == CMSG_LEN(sizeof(int)) && cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) sock = *((int*)CMSG_DATA(cmsg)); else { sock = -1; } reply.data.stat.retval = bind(sock, (struct sockaddr *)&request.data.bind.addr, sizeof request.data.bind.addr); if (reply.data.stat.retval < 0) reply.data.stat.error = errno; #if DEBUG_TESTING /* Sleep to check for races */ if( options.wait!=0 ) sleep(options.wait); #endif if (send(sv[1], &reply, sizeof reply, 0) != sizeof reply) perror("privbind: send"); if (sock > -1 && close(sock)) perror("privbind: close"); break; default: fprintf(stderr, "privbind: bad request type: %d\n", request.type); break; } } else { fprintf(stderr, "privbind: empty request\n"); } } else if (recvbytes == 0) { /* If the child closed its end of the socket, it means the child has exited. We have nothing more to do. */ return 0; } else { perror("privbind: recvmsg"); } } while (options.numbinds == 0 || --options.numbinds > 0); /* If we got here, the child has done the number of binds specified by the -n option, and we have nothing more to do and should exit, leaving behind no helper process */ return 0; }
int main(int argc, char *argv[]) { struct msghdr msgh; struct iovec iov; int data, lfd, sfd, fd, opt; ssize_t nr; int use_datagram_socket; union { struct cmsghdr cmh; char control[CMSG_SPACE(sizeof(int))]; /* Space large enough to hold an 'int' */ } control_un; struct cmsghdr *cmhp; /* Parse command-line arguments */ use_datagram_socket = 0; while ((opt = getopt(argc, argv, "d")) != -1) { switch (opt) { case 'd': use_datagram_socket = 1; break; default: usage(stderr, argv[0]); exit(EXIT_FAILURE); } } /* Create socket bound to well-known address */ if (remove(SOCK_PATH) == -1 && errno != ENOENT) { fprintf(stderr, "remove-%s\n", SOCK_PATH); exit(EXIT_FAILURE); } if (use_datagram_socket) { fprintf(stderr, "Receiving via datagram socket\n"); sfd = unix_bind(SOCK_PATH, SOCK_DGRAM); if (sfd == -1) { perror("unix_bind"); exit(EXIT_FAILURE); } } else { fprintf(stderr, "Receiving via stream socket\n"); lfd = unix_listen(SOCK_PATH, 5); if (lfd == -1) { perror("unix_listen"); exit(EXIT_FAILURE); } sfd = accept(lfd, NULL, 0); if (sfd == -1) { perror("accept"); exit(EXIT_FAILURE); } } /* Set 'control_un' to describe ancillary data that we want to receive */ control_un.cmh.cmsg_len = CMSG_LEN(sizeof(int)); control_un.cmh.cmsg_level = SOL_SOCKET; control_un.cmh.cmsg_type = SCM_RIGHTS; /* Set 'msgh' fields to describe 'control_un' */ msgh.msg_control = control_un.control; msgh.msg_controllen = sizeof(control_un.control); /* Set fields of 'msgh' to point to buffer used to receive (real) data read by recvmsg() */ msgh.msg_iov = &iov; msgh.msg_iovlen = 1; iov.iov_base = &data; iov.iov_len = sizeof(int); msgh.msg_name = NULL; /* We don't need address of peer */ msgh.msg_namelen = 0; /* Receive real plus ancillary data */ nr = recvmsg(sfd, &msgh, 0); if (nr == -1) { perror("recvmsg"); exit(EXIT_FAILURE); } fprintf(stderr, "recvmsg() returned %ld\n", (long) nr); if (nr > 0) { fprintf(stderr, "Received data = %d\n", data); } /* Get the received file descriptor (which is typically a different file descriptor number than was used in the sending process) */ cmhp = CMSG_FIRSTHDR(&msgh); if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(int))) { fprintf(stderr, "bad cmsg header / message length\n"); exit(EXIT_FAILURE); } if (cmhp->cmsg_level != SOL_SOCKET) { fprintf(stderr, "cmsg_level != SOL_SOCKET\n"); exit(EXIT_FAILURE); } if (cmhp->cmsg_type != SCM_RIGHTS) { fprintf(stderr, "cmsg_type != SCM_RIGHTS\n"); exit(EXIT_FAILURE); } fd = *((int *) CMSG_DATA(cmhp)); fprintf(stderr, "Received fd=%d\n", fd); /* Having obtained the file descriptor, read the file's contents and print them on standard output */ while (1) { char buf[BUF_SIZE]; ssize_t numRead; numRead = read(fd, buf, BUF_SIZE); if (numRead == -1) { perror("read"); exit(EXIT_FAILURE); } if (numRead == 0) { break; } write(STDOUT_FILENO, buf, numRead); } exit(EXIT_SUCCESS); }
/** * Process the message and add/drop multicast membership if needed */ int ProcessInterfaceWatch(int s, int s_ssdp, int s_ssdp6, int n_if_addr, const char * * if_addr) { ssize_t len; int i; char buffer[4096]; #ifdef __linux__ struct iovec iov; struct msghdr hdr; struct nlmsghdr *nlhdr; struct ifaddrmsg *ifa; struct rtattr *rta; int ifa_len; iov.iov_base = buffer; iov.iov_len = sizeof(buffer); memset(&hdr, 0, sizeof(hdr)); hdr.msg_iov = &iov; hdr.msg_iovlen = 1; len = recvmsg(s, &hdr, 0); if(len < 0) { syslog(LOG_ERR, "recvmsg(s, &hdr, 0): %m"); return -1; } for(nlhdr = (struct nlmsghdr *)buffer; NLMSG_OK(nlhdr, len); nlhdr = NLMSG_NEXT(nlhdr, len)) { int is_del = 0; char address[48]; char ifname[IFNAMSIZ]; address[0] = '\0'; ifname[0] = '\0'; if(nlhdr->nlmsg_type == NLMSG_DONE) break; switch(nlhdr->nlmsg_type) { /* case RTM_NEWLINK: */ /* case RTM_DELLINK: */ case RTM_DELADDR: is_del = 1; case RTM_NEWADDR: /* http://linux-hacks.blogspot.fr/2009/01/sample-code-to-learn-netlink.html */ ifa = (struct ifaddrmsg *)NLMSG_DATA(nlhdr); rta = (struct rtattr *)IFA_RTA(ifa); ifa_len = IFA_PAYLOAD(nlhdr); syslog(LOG_DEBUG, "%s %s index=%d fam=%d prefixlen=%d flags=%d scope=%d", "ProcessInterfaceWatchNotify", is_del ? "RTM_DELADDR" : "RTM_NEWADDR", ifa->ifa_index, ifa->ifa_family, ifa->ifa_prefixlen, ifa->ifa_flags, ifa->ifa_scope); for(;RTA_OK(rta, ifa_len); rta = RTA_NEXT(rta, ifa_len)) { /*RTA_DATA(rta)*/ /*rta_type : IFA_ADDRESS, IFA_LOCAL, etc. */ char tmp[128]; memset(tmp, 0, sizeof(tmp)); switch(rta->rta_type) { case IFA_ADDRESS: case IFA_LOCAL: case IFA_BROADCAST: case IFA_ANYCAST: inet_ntop(ifa->ifa_family, RTA_DATA(rta), tmp, sizeof(tmp)); if(rta->rta_type == IFA_ADDRESS) strncpy(address, tmp, sizeof(address)); break; case IFA_LABEL: strncpy(tmp, RTA_DATA(rta), sizeof(tmp)); strncpy(ifname, tmp, sizeof(ifname)); break; case IFA_CACHEINFO: { struct ifa_cacheinfo *cache_info; cache_info = RTA_DATA(rta); snprintf(tmp, sizeof(tmp), "valid=%u prefered=%u", cache_info->ifa_valid, cache_info->ifa_prefered); } break; default: strncpy(tmp, "*unknown*", sizeof(tmp)); } syslog(LOG_DEBUG, " rta_len=%d rta_type=%d '%s'", rta->rta_len, rta->rta_type, tmp); } syslog(LOG_INFO, "%s: %s/%d %s", is_del ? "RTM_DELADDR" : "RTM_NEWADDR", address, ifa->ifa_prefixlen, ifname); for(i = 0; i < n_if_addr; i++) { if((0 == strcmp(address, if_addr[i])) || (0 == strcmp(ifname, if_addr[i])) || (ifa->ifa_index == if_nametoindex(if_addr[i]))) { if(ifa->ifa_family == AF_INET && address[0] != '\0') AddDropMulticastMembership(s_ssdp, address, 0, is_del); else if(ifa->ifa_family == AF_INET6) AddDropMulticastMembership(s_ssdp6, if_addr[i], 1, is_del); break; } } break; default: syslog(LOG_DEBUG, "unknown nlmsg_type=%d", nlhdr->nlmsg_type); } } #else /* __linux__ */ struct rt_msghdr * rtm; struct ifa_msghdr * ifam; int is_del = 0; char tmp[64]; char * p; struct sockaddr * sa; int addr; char address[48]; char ifname[IFNAMSIZ]; int family = AF_UNSPEC; int prefixlen = 0; address[0] = '\0'; ifname[0] = '\0'; len = recv(s, buffer, sizeof(buffer), 0); if(len < 0) { syslog(LOG_ERR, "%s recv: %m", "ProcessInterfaceWatchNotify"); return -1; } rtm = (struct rt_msghdr *)buffer; switch(rtm->rtm_type) { case RTM_DELADDR: is_del = 1; case RTM_NEWADDR: ifam = (struct ifa_msghdr *)buffer; syslog(LOG_DEBUG, "%s %s len=%d/%hu index=%hu addrs=%x flags=%x", "ProcessInterfaceWatchNotify", is_del?"RTM_DELADDR":"RTM_NEWADDR", (int)len, ifam->ifam_msglen, ifam->ifam_index, ifam->ifam_addrs, ifam->ifam_flags); p = buffer + sizeof(struct ifa_msghdr); addr = 1; while(p < buffer + len) { sa = (struct sockaddr *)p; while(!(addr & ifam->ifam_addrs) && (addr <= ifam->ifam_addrs)) addr = addr << 1; sockaddr_to_string(sa, tmp, sizeof(tmp)); syslog(LOG_DEBUG, " %s", tmp); switch(addr) { case RTA_DST: case RTA_GATEWAY: break; case RTA_NETMASK: if(sa->sa_family == AF_INET #if defined(__OpenBSD__) || (sa->sa_family == 0 && sa->sa_len <= sizeof(struct sockaddr_in)) #endif ) { uint32_t sin_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); while((prefixlen < 32) && ((sin_addr & (1 << (31 - prefixlen))) != 0)) prefixlen++; } else if(sa->sa_family == AF_INET6 #if defined(__OpenBSD__) || (sa->sa_family == 0 && sa->sa_len == sizeof(struct sockaddr_in6)) #endif ) { int i = 0; uint8_t * q = ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; while((*q == 0xff) && (i < 16)) { prefixlen += 8; q++; i++; } if(i < 16) { i = 0; while((i < 8) && ((*q & (1 << (7 - i))) != 0)) i++; prefixlen += i; } } break; case RTA_GENMASK: break; case RTA_IFP: #ifdef AF_LINK if(sa->sa_family == AF_LINK) { struct sockaddr_dl * sdl = (struct sockaddr_dl *)sa; memset(ifname, 0, sizeof(ifname)); memcpy(ifname, sdl->sdl_data, sdl->sdl_nlen); } #endif break; case RTA_IFA: family = sa->sa_family; if(sa->sa_family == AF_INET) { inet_ntop(sa->sa_family, &((struct sockaddr_in *)sa)->sin_addr, address, sizeof(address)); } else if(sa->sa_family == AF_INET6) { inet_ntop(sa->sa_family, &((struct sockaddr_in6 *)sa)->sin6_addr, address, sizeof(address)); } break; case RTA_AUTHOR: break; case RTA_BRD: break; } #if 0 syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x", (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3], (uint8_t)p[0], (uint8_t)p[1], (uint8_t)p[2], (uint8_t)p[3]); syslog(LOG_DEBUG, " %d.%d.%d.%d %02x%02x%02x%02x", (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7], (uint8_t)p[4], (uint8_t)p[5], (uint8_t)p[6], (uint8_t)p[7]); #endif p += SA_RLEN(sa); addr = addr << 1; } syslog(LOG_INFO, "%s: %s/%d %s", is_del ? "RTM_DELADDR" : "RTM_NEWADDR", address, prefixlen, ifname); for(i = 0; i < n_if_addr; i++) { if(0 == strcmp(address, if_addr[i]) || 0 == strcmp(ifname, if_addr[i]) || ifam->ifam_index == if_nametoindex(if_addr[i])) { if(family == AF_INET && address[0] != '\0') AddDropMulticastMembership(s_ssdp, address, 0, is_del); else if(family == AF_INET6) AddDropMulticastMembership(s_ssdp6, if_addr[i], 1, is_del); break; } } break; default: syslog(LOG_DEBUG, "Unknown RTM message : rtm->rtm_type=%d len=%d", rtm->rtm_type, (int)len); } #endif return 0; }
static void uv__read(uv_stream_t* stream) { uv_buf_t buf; ssize_t nread; struct msghdr msg; struct cmsghdr* cmsg; char cmsg_space[64]; int count; /* Prevent loop starvation when the data comes in as fast as (or faster than) * we can read it. XXX Need to rearm fd if we switch to edge-triggered I/O. */ count = 32; /* XXX: Maybe instead of having UV_STREAM_READING we just test if * tcp->read_cb is NULL or not? */ while ((stream->read_cb || stream->read2_cb) && (stream->flags & UV_STREAM_READING) && (count-- > 0)) { assert(stream->alloc_cb); buf = stream->alloc_cb((uv_handle_t*)stream, 64 * 1024); assert(buf.len > 0); assert(buf.base); assert(uv__stream_fd(stream) >= 0); if (stream->read_cb) { do { nread = read(uv__stream_fd(stream), buf.base, buf.len); } while (nread < 0 && errno == EINTR); } else { assert(stream->read2_cb); /* read2_cb uses recvmsg */ msg.msg_flags = 0; msg.msg_iov = (struct iovec*) &buf; msg.msg_iovlen = 1; msg.msg_name = NULL; msg.msg_namelen = 0; /* Set up to receive a descriptor even if one isn't in the message */ msg.msg_controllen = 64; msg.msg_control = (void *) cmsg_space; do { nread = recvmsg(uv__stream_fd(stream), &msg, 0); } while (nread < 0 && errno == EINTR); } #define INVOKE_READ_CB(stream, status, buf, type) \ do { \ if ((stream)->read_cb != NULL) \ (stream)->read_cb((stream), (status), (buf)); \ else \ (stream)->read2_cb((uv_pipe_t*) (stream), (status), (buf), (type)); \ } \ while (0) if (nread < 0) { /* Error */ if (errno == EAGAIN || errno == EWOULDBLOCK) { /* Wait for the next one. */ if (stream->flags & UV_STREAM_READING) { uv__io_start(stream->loop, &stream->io_watcher, UV__POLLIN); } uv__set_sys_error(stream->loop, EAGAIN); INVOKE_READ_CB(stream, 0, buf, UV_UNKNOWN_HANDLE); } else { /* Error. User should call uv_close(). */ uv__set_sys_error(stream->loop, errno); INVOKE_READ_CB(stream, -1, buf, UV_UNKNOWN_HANDLE); assert(!uv__io_active(&stream->io_watcher, UV__POLLIN) && "stream->read_cb(status=-1) did not call uv_close()"); } return; } else if (nread == 0) { /* EOF */ uv__io_stop(stream->loop, &stream->io_watcher, UV__POLLIN); if (!uv__io_active(&stream->io_watcher, UV__POLLOUT)) uv__handle_stop(stream); uv__set_artificial_error(stream->loop, UV_EOF); INVOKE_READ_CB(stream, -1, buf, UV_UNKNOWN_HANDLE); return; } else { /* Successful read */ ssize_t buflen = buf.len; if (stream->read_cb) { stream->read_cb(stream, nread, buf); } else { assert(stream->read2_cb); /* * XXX: Some implementations can send multiple file descriptors in a * single message. We should be using CMSG_NXTHDR() to walk the * chain to get at them all. This would require changing the API to * hand these back up the caller, is a pain. */ for (cmsg = CMSG_FIRSTHDR(&msg); msg.msg_controllen > 0 && cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_type == SCM_RIGHTS) { if (stream->accepted_fd != -1) { fprintf(stderr, "(libuv) ignoring extra FD received\n"); } /* silence aliasing warning */ { void* pv = CMSG_DATA(cmsg); int* pi = pv; stream->accepted_fd = *pi; } } else { fprintf(stderr, "ignoring non-SCM_RIGHTS ancillary data: %d\n", cmsg->cmsg_type); } } if (stream->accepted_fd >= 0) { stream->read2_cb((uv_pipe_t*)stream, nread, buf, uv__handle_type(stream->accepted_fd)); } else { stream->read2_cb((uv_pipe_t*)stream, nread, buf, UV_UNKNOWN_HANDLE); } } /* Return if we didn't fill the buffer, there is no more data to read. */ if (nread < buflen) { return; } } } }
int myrecvfrom (int s, void *buf, int len, unsigned int flags, struct sockaddr *from, int *fromlen, struct sockaddr_in *myaddr) { struct msghdr msg; struct iovec iov[1]; int n; struct cmsghdr *cmptr; union { struct cmsghdr cm; #ifdef IP_PKTINFO char control[CMSG_SPACE (sizeof (struct in_addr)) + CMSG_SPACE (sizeof (struct in_pktinfo))]; #else char control[CMSG_SPACE (sizeof (struct in_addr))]; #endif } control_un; int on = 1; #ifdef IP_PKTINFO struct in_pktinfo pktinfo; #endif /* Try to enable getting the return address */ #ifdef IP_RECVDSTADDR setsockopt (s, IPPROTO_IP, IP_RECVDSTADDR, &on, sizeof (on)); #endif #ifdef IP_PKTINFO setsockopt (s, IPPROTO_IP, IP_PKTINFO, &on, sizeof (on)); #endif msg.msg_control = control_un.control; msg.msg_controllen = sizeof (control_un.control); msg.msg_flags = 0; msg.msg_name = from; msg.msg_namelen = *fromlen; iov[0].iov_base = buf; iov[0].iov_len = len; msg.msg_iov = iov; msg.msg_iovlen = 1; if ((n = recvmsg (s, &msg, flags)) < 0) return n; /* Error */ *fromlen = msg.msg_namelen; if (myaddr) { bzero (myaddr, sizeof (struct sockaddr_in)); myaddr->sin_family = AF_INET; if (msg.msg_controllen < sizeof (struct cmsghdr) || (msg.msg_flags & MSG_CTRUNC)) return n; /* No information available */ for (cmptr = CMSG_FIRSTHDR (&msg); cmptr != NULL; cmptr = CMSG_NXTHDR (&msg, cmptr)) { #ifdef IP_RECVSTDADDR if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_RECVDSTADDR) { memcpy (&myaddr->sin_addr, CMSG_DATA (cmptr), sizeof (struct in_addr)); } #endif #ifdef IP_PKTINFO if (cmptr->cmsg_level == IPPROTO_IP && cmptr->cmsg_type == IP_PKTINFO) { memcpy (&pktinfo, CMSG_DATA (cmptr), sizeof (struct in_pktinfo)); memcpy (&myaddr->sin_addr, &pktinfo.ipi_addr, sizeof (struct in_addr)); } #endif } } return n; }
void main_loop(ping_func_set_st *fset, socket_st *sock, __u8 *packet, int packlen) { char addrbuf[128]; char ans_data[4096]; struct iovec iov; struct msghdr msg; struct cmsghdr *c; int cc; int next; int polling; iov.iov_base = (char *)packet; for (;;) { /* Check exit conditions. */ if (exiting) break; if (npackets && nreceived + nerrors >= npackets) break; if (deadline && nerrors) break; /* Check for and do special actions. */ if (status_snapshot) status(); /* Send probes scheduled to this time. */ do { next = pinger(fset, sock); next = schedule_exit(next); } while (next <= 0); /* "next" is time to send next probe, if positive. * If next<=0 send now or as soon as possible. */ /* Technical part. Looks wicked. Could be dropped, * if everyone used the newest kernel. :-) * Its purpose is: * 1. Provide intervals less than resolution of scheduler. * Solution: spinning. * 2. Avoid use of poll(), when recvmsg() can provide * timed waiting (SO_RCVTIMEO). */ polling = 0; if ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || next<SCHINT(interval)) { int recv_expected = in_flight(); /* If we are here, recvmsg() is unable to wait for * required timeout. */ if (1000 % HZ == 0 ? next <= 1000 / HZ : (next < INT_MAX / HZ && next * HZ <= 1000)) { /* Very short timeout... So, if we wait for * something, we sleep for MININTERVAL. * Otherwise, spin! */ if (recv_expected) { next = MININTERVAL; } else { next = 0; /* When spinning, no reasons to poll. * Use nonblocking recvmsg() instead. */ polling = MSG_DONTWAIT; /* But yield yet. */ sched_yield(); } } if (!polling && ((options & (F_ADAPTIVE|F_FLOOD_POLL)) || interval)) { struct pollfd pset; pset.fd = sock->fd; pset.events = POLLIN; pset.revents = 0; if (poll(&pset, 1, next) < 1 || !(pset.revents&(POLLIN|POLLERR))) continue; polling = MSG_DONTWAIT; } } for (;;) { struct timeval *recv_timep = NULL; struct timeval recv_time; int not_ours = 0; /* Raw socket can receive messages * destined to other running pings. */ iov.iov_len = packlen; memset(&msg, 0, sizeof(msg)); msg.msg_name = addrbuf; msg.msg_namelen = sizeof(addrbuf); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = ans_data; msg.msg_controllen = sizeof(ans_data); cc = recvmsg(sock->fd, &msg, polling); polling = MSG_DONTWAIT; if (cc < 0) { if (errno == EAGAIN || errno == EINTR) break; if (!fset->receive_error_msg(sock)) { if (errno) { perror("ping: recvmsg"); break; } not_ours = 1; } } else { #ifdef SO_TIMESTAMP for (c = CMSG_FIRSTHDR(&msg); c; c = CMSG_NXTHDR(&msg, c)) { if (c->cmsg_level != SOL_SOCKET || c->cmsg_type != SO_TIMESTAMP) continue; if (c->cmsg_len < CMSG_LEN(sizeof(struct timeval))) continue; recv_timep = (struct timeval*)CMSG_DATA(c); } #endif if ((options&F_LATENCY) || recv_timep == NULL) { if ((options&F_LATENCY) || ioctl(sock->fd, SIOCGSTAMP, &recv_time)) gettimeofday(&recv_time, NULL); recv_timep = &recv_time; } not_ours = fset->parse_reply(sock, &msg, cc, addrbuf, recv_timep); } /* See? ... someone runs another ping on this host. */ if (not_ours && sock->socktype == SOCK_RAW) fset->install_filter(sock); /* If nothing is in flight, "break" returns us to pinger. */ if (in_flight() == 0) break; /* Otherwise, try to recvmsg() again. recvmsg() * is nonblocking after the first iteration, so that * if nothing is queued, it will receive EAGAIN * and return to pinger. */ } } finish(); }
int receive_fd(int unix_socket, void* data, int data_len, int* fd) { struct msghdr msg; struct iovec iov[1]; int new_fd; int ret; int n; #ifdef HAVE_MSGHDR_MSG_CONTROL struct cmsghdr* cmsg; union{ struct cmsghdr cm; char control[CMSG_SPACE(sizeof(new_fd))]; }control_un; msg.msg_control=control_un.control; msg.msg_controllen=sizeof(control_un.control); #else msg.msg_accrights=(caddr_t) &new_fd; msg.msg_accrightslen=sizeof(int); #endif msg.msg_name=0; msg.msg_namelen=0; iov[0].iov_base=data; iov[0].iov_len=data_len; msg.msg_iov=iov; msg.msg_iovlen=1; again: ret=recvmsg(unix_socket, &msg, MSG_WAITALL); if (ret<0){ if (errno==EINTR) goto again; LOG(L_CRIT, "ERROR: receive_fd: recvmsg on %d failed: %s\n", unix_socket, strerror(errno)); goto error; } if (ret==0){ /* EOF */ LOG(L_CRIT, "ERROR: receive_fd: EOF on %d\n", unix_socket); goto error; } if (ret<data_len){ LOG(L_WARN, "WARNING: receive_fd: too few bytes read (%d from %d)" "trying to fix...\n", ret, data_len); n=recv_all(unix_socket, (char*)data+ret, data_len-ret); if (n>=0) ret+=n; else{ ret=n; goto error; } } #ifdef HAVE_MSGHDR_MSG_CONTROL cmsg=CMSG_FIRSTHDR(&msg); if ((cmsg!=0) && (cmsg->cmsg_len==CMSG_LEN(sizeof(new_fd)))){ if (cmsg->cmsg_type!= SCM_RIGHTS){ LOG(L_ERR, "ERROR: receive_fd: msg control type != SCM_RIGHTS\n"); ret=-1; goto error; } if (cmsg->cmsg_level!= SOL_SOCKET){ LOG(L_ERR, "ERROR: receive_fd: msg level != SOL_SOCKET\n"); ret=-1; goto error; } *fd=*((int*) CMSG_DATA(cmsg)); }else{ LOG(L_ERR, "ERROR: receive_fd: no descriptor passed, cmsg=%p," "len=%d\n", cmsg, (unsigned)cmsg->cmsg_len); *fd=-1; /* it's not really an error */ } #else if (msg.msg_accrightslen==sizeof(int)){ *fd=new_fd; }else{ LOG(L_ERR, "ERROR: receive_fd: no descriptor passed," " accrightslen=%d\n", msg.msg_accrightslen); *fd=-1; } #endif error: return ret; }
static void recvaddrs(int fd, struct ifaddrs **ifa, __u32 seq) { char buf[8192]; struct sockaddr_nl nladdr; struct iovec iov = { buf, sizeof(buf) }; struct ifaddrmsg *m; struct rtattr * rta_tb[IFA_MAX+1]; struct ifaddrs *I; while (1) { int status; struct nlmsghdr *h; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), &iov, 1, NULL, 0, 0 }; status = recvmsg(fd, &msg, 0); if (status < 0) continue; if (status == 0) return; h = (struct nlmsghdr*)buf; while (NLMSG_OK(h, status)) { if (h->nlmsg_seq != seq) goto skip_it; if (h->nlmsg_type == NLMSG_DONE) return; if (h->nlmsg_type == NLMSG_ERROR) return; if (h->nlmsg_type != RTM_NEWADDR) goto skip_it; m = NLMSG_DATA(h); if (m->ifa_family != AF_INET && m->ifa_family != AF_INET6) goto skip_it; if (m->ifa_flags&IFA_F_TENTATIVE) goto skip_it; memset(rta_tb, 0, sizeof(rta_tb)); parse_rtattr(rta_tb, IFA_MAX, IFA_RTA(m), h->nlmsg_len - NLMSG_LENGTH(sizeof(*m))); if (rta_tb[IFA_LOCAL] == NULL) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; if (rta_tb[IFA_LOCAL] == NULL) goto skip_it; I = malloc(sizeof(struct ifaddrs)); if (!I) return; memset(I, 0, sizeof(*I)); I->ifa_ifindex = m->ifa_index; I->ifa_addr = (struct sockaddr*)&I->ifa_addrbuf; I->ifa_addr->sa_family = m->ifa_family; if (m->ifa_family == AF_INET) { struct sockaddr_in *sin = (void*)I->ifa_addr; memcpy(&sin->sin_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 4); } else { struct sockaddr_in6 *sin = (void*)I->ifa_addr; memcpy(&sin->sin6_addr, RTA_DATA(rta_tb[IFA_LOCAL]), 16); if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr)) sin->sin6_scope_id = I->ifa_ifindex; } I->ifa_next = *ifa; *ifa = I; skip_it: h = NLMSG_NEXT(h, status); } if (msg.msg_flags & MSG_TRUNC) continue; } return; }
/* * This function runs in the context of the background proxy process. * Receive a control message from the parent (sent by the port_share_sendmsg * function above) and act on it. Return false if the proxy process should * exit, true otherwise. */ static bool control_message_from_parent(const socket_descriptor_t sd_control, struct proxy_connection **list, struct event_set *es, const struct sockaddr_in server_addr, const int max_initial_buf, const char *journal_dir) { /* this buffer needs to be large enough to handle the largest buffer * that might be returned by the link_socket_read call in read_incoming_link. */ struct buffer buf = alloc_buf(max_initial_buf); struct msghdr mesg; struct cmsghdr *h; struct iovec iov[2]; char command = 0; ssize_t status; int ret = true; CLEAR(mesg); iov[0].iov_base = &command; iov[0].iov_len = sizeof(command); iov[1].iov_base = BPTR(&buf); iov[1].iov_len = BCAP(&buf); mesg.msg_iov = iov; mesg.msg_iovlen = 2; mesg.msg_controllen = cmsg_size(); mesg.msg_control = (char *) malloc(mesg.msg_controllen); check_malloc_return(mesg.msg_control); mesg.msg_flags = 0; h = CMSG_FIRSTHDR(&mesg); h->cmsg_len = CMSG_LEN(sizeof(socket_descriptor_t)); h->cmsg_level = SOL_SOCKET; h->cmsg_type = SCM_RIGHTS; static const socket_descriptor_t socket_undefined = SOCKET_UNDEFINED; memcpy(CMSG_DATA(h), &socket_undefined, sizeof(socket_undefined)); status = recvmsg(sd_control, &mesg, MSG_NOSIGNAL); if (status != -1) { if (h == NULL || h->cmsg_len != CMSG_LEN(sizeof(socket_descriptor_t)) || h->cmsg_level != SOL_SOCKET || h->cmsg_type != SCM_RIGHTS) { msg(M_WARN, "PORT SHARE PROXY: received unknown message"); } else { socket_descriptor_t received_fd; memcpy(&received_fd, CMSG_DATA(h), sizeof(received_fd)); dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED sd=%d", (int)received_fd); if (status >= 2 && command == COMMAND_REDIRECT) { buf.len = status - 1; if (proxy_entry_new(list, es, server_addr, received_fd, &buf, journal_dir)) { CLEAR(buf); /* we gave the buffer to proxy_entry_new */ } else { openvpn_close_socket(received_fd); } } else if (status >= 1 && command == COMMAND_EXIT) { dmsg(D_PS_PROXY_DEBUG, "PORT SHARE PROXY: RECEIVED COMMAND_EXIT"); openvpn_close_socket(received_fd); /* null socket */ ret = false; } } } free(mesg.msg_control); free_buf(&buf); return ret; }
/* Query all of the listed hosts */ static void query_loop(char *argv[], int argc, int soc) { #define NA0 (OMSG.rip_auths[0]) #define NA2 (OMSG.rip_auths[2]) struct seen { struct seen *next; struct in_addr addr; } *seen, *sp; int answered = 0; int cc; fd_set bits; struct timeval now, delay; struct sockaddr_in from; MD5_CTX md5_ctx; struct msghdr msg; uint_t ifindex; struct iovec iov; uint8_t ancillary_data[CONTROL_BUFSIZE]; OMSG.rip_cmd = (pflag) ? RIPCMD_POLL : RIPCMD_REQUEST; if (ripv2) { OMSG.rip_vers = RIPv2; if (auth_type == RIP_AUTH_PW) { OMSG.rip_nets[1] = OMSG.rip_nets[0]; NA0.a_family = RIP_AF_AUTH; NA0.a_type = RIP_AUTH_PW; (void) memcpy(NA0.au.au_pw, passwd, RIP_AUTH_PW_LEN); omsg_len += sizeof (OMSG.rip_nets[0]); } else if (auth_type == RIP_AUTH_MD5) { OMSG.rip_nets[1] = OMSG.rip_nets[0]; NA0.a_family = RIP_AF_AUTH; NA0.a_type = RIP_AUTH_MD5; NA0.au.a_md5.md5_keyid = (int8_t)keyid; NA0.au.a_md5.md5_auth_len = RIP_AUTH_MD5_LEN; NA0.au.a_md5.md5_seqno = 0; cc = (char *)&NA2-(char *)&OMSG; NA0.au.a_md5.md5_pkt_len = htons(cc); NA2.a_family = RIP_AF_AUTH; NA2.a_type = RIP_AUTH_TRAILER; MD5Init(&md5_ctx); MD5Update(&md5_ctx, (uchar_t *)&OMSG, cc+4); MD5Update(&md5_ctx, (uchar_t *)passwd, RIP_AUTH_MD5_LEN); MD5Final(NA2.au.au_pw, &md5_ctx); omsg_len += 2*sizeof (OMSG.rip_nets[0]); } } else { OMSG.rip_vers = RIPv1; OMSG.rip_nets[0].n_mask = 0; } /* ask the first (valid) host */ seen = NULL; while (0 > out(*argv++, soc)) { if (*argv == NULL) exit(EXIT_FAILURE); answered++; } iov.iov_base = &imsg_buf; iov.iov_len = sizeof (imsg_buf); msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_name = &from; msg.msg_control = &ancillary_data; (void) FD_ZERO(&bits); FD_SET(soc, &bits); for (;;) { delay.tv_sec = 0; delay.tv_usec = STIME; cc = select(soc+1, &bits, 0, 0, &delay); if (cc > 0) { msg.msg_namelen = sizeof (from); msg.msg_controllen = sizeof (ancillary_data); cc = recvmsg(soc, &msg, 0); if (cc < 0) { perror("rtquery: recvmsg"); exit(EXIT_FAILURE); } /* avoid looping on high traffic */ if (answered > argc + 200) break; /* * count the distinct responding hosts. * You cannot match responding hosts with * addresses to which queries were transmitted, * because a router might respond with a * different source address. */ for (sp = seen; sp != NULL; sp = sp->next) { if (sp->addr.s_addr == from.sin_addr.s_addr) break; } if (sp == NULL) { sp = malloc(sizeof (*sp)); if (sp != NULL) { sp->addr = from.sin_addr; sp->next = seen; seen = sp; } else { perror("rtquery: malloc"); } answered++; } ifindex = incoming_interface(&msg); rip_input(&from, cc, ifindex); continue; } if (cc < 0) { if (errno == EINTR) continue; perror("rtquery: select"); exit(EXIT_FAILURE); } /* * After a pause in responses, probe another host. * This reduces the intermingling of answers. */ while (*argv != NULL && 0 > out(*argv++, soc)) answered++; /* * continue until no more packets arrive * or we have heard from all hosts */ if (answered >= argc) break; /* or until we have waited a long time */ if (gettimeofday(&now, 0) < 0) { perror("rtquery: gettimeofday"); exit(EXIT_FAILURE); } if (sent.tv_sec + wtime <= now.tv_sec) break; } /* fail if there was no answer */ exit(answered >= argc ? EXIT_SUCCESS : EXIT_FAILURE); }
static int print_interfaces() { int sock, len; struct nlmsghdr *nlm; struct iovec iov; struct msghdr rtnl_msg; struct sockaddr_nl s_nl; struct { struct nlmsghdr nh; struct rtgenmsg rtgm; } req; char buf[8192]; printf("Network interfaces:\n"); /* open netlink socket */ sock = socket(AF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); if (sock < 0) { perror("sock"); return 1; } /* initialize request */ memset(&req, 0, sizeof(req)); req.nh.nlmsg_len = NLMSG_LENGTH(sizeof(req.rtgm)); req.nh.nlmsg_type = RTM_GETLINK; req.nh.nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; req.nh.nlmsg_seq = 1; req.nh.nlmsg_pid = getpid(); req.rtgm.rtgen_family = AF_PACKET; memset(&s_nl, 0, sizeof(s_nl)); s_nl.nl_family = AF_NETLINK; iov.iov_base = &req; iov.iov_len = req.nh.nlmsg_len; memset(&rtnl_msg, 0, sizeof(rtnl_msg)); rtnl_msg.msg_iov = &iov; rtnl_msg.msg_iovlen = 1; rtnl_msg.msg_name = &s_nl; rtnl_msg.msg_namelen = sizeof(s_nl); /* send request */ len = sendmsg(sock, &rtnl_msg, 0); if (len < 0) { perror("sendmsg"); close(sock); return 1; } int end = 0; while (!end) { iov.iov_base = buf; iov.iov_len = sizeof(buf); memset(&rtnl_msg, 0, sizeof(rtnl_msg)); rtnl_msg.msg_iov = &iov; rtnl_msg.msg_iovlen = 1; rtnl_msg.msg_name = &s_nl; rtnl_msg.msg_namelen = sizeof(s_nl); /* receive response */ len = recvmsg(sock, &rtnl_msg, 0); if (len < 0) { perror("recvmsg"); close(sock); return 1; } /* read response */ nlm = (struct nlmsghdr*)buf; while (NLMSG_OK(nlm, len)) { if (nlm->nlmsg_type == NLMSG_DONE) { end = 1; break; } else if (nlm->nlmsg_type == RTM_NEWLINK) { struct ifinfomsg *ifinfo; struct rtattr *rta; int iflen; ifinfo = NLMSG_DATA(nlm); rta = IFLA_RTA(ifinfo); iflen = IFLA_PAYLOAD(nlm); while (RTA_OK(rta, iflen)) { if (rta->rta_type == IFLA_IFNAME) printf(" %s\n", (char*)RTA_DATA(rta)); rta = RTA_NEXT(rta, iflen); } } nlm = NLMSG_NEXT(nlm, len); } } close(sock); return 0; }
static int dgram_sctp_read(BIO *b, char *out, int outl) { int ret = 0, n = 0, i, optval; socklen_t optlen; bio_dgram_sctp_data *data = (bio_dgram_sctp_data *)b->ptr; union sctp_notification *snp; struct msghdr msg; struct iovec iov; struct cmsghdr *cmsg; char cmsgbuf[512]; if (out != NULL) { clear_socket_error(); do { memset(&data->rcvinfo, 0x00, sizeof(struct bio_dgram_sctp_rcvinfo)); iov.iov_base = out; iov.iov_len = outl; msg.msg_name = NULL; msg.msg_namelen = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = cmsgbuf; msg.msg_controllen = 512; msg.msg_flags = 0; n = recvmsg(b->num, &msg, 0); if (n <= 0) { if (n < 0) ret = n; break; } if (msg.msg_controllen > 0) { for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level != IPPROTO_SCTP) continue; #ifdef SCTP_RCVINFO if (cmsg->cmsg_type == SCTP_RCVINFO) { struct sctp_rcvinfo *rcvinfo; rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); data->rcvinfo.rcv_sid = rcvinfo->rcv_sid; data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn; data->rcvinfo.rcv_flags = rcvinfo->rcv_flags; data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid; data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn; data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn; data->rcvinfo.rcv_context = rcvinfo->rcv_context; } #endif #ifdef SCTP_SNDRCV if (cmsg->cmsg_type == SCTP_SNDRCV) { struct sctp_sndrcvinfo *sndrcvinfo; sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream; data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn; data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags; data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid; data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn; data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn; data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context; } #endif } } if (msg.msg_flags & MSG_NOTIFICATION) { snp = (union sctp_notification*) out; if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { #ifdef SCTP_EVENT struct sctp_event event; #else struct sctp_event_subscribe event; socklen_t eventsize; #endif /* If a message has been delayed until the socket * is dry, it can be sent now. */ if (data->saved_message.length > 0) { dgram_sctp_write(data->saved_message.bio, data->saved_message.data, data->saved_message.length); OPENSSL_free(data->saved_message.data); data->saved_message.length = 0; } /* disable sender dry event */ #ifdef SCTP_EVENT memset(&event, 0, sizeof(struct sctp_event)); event.se_assoc_id = 0; event.se_type = SCTP_SENDER_DRY_EVENT; event.se_on = 0; i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof(struct sctp_event)); OPENSSL_assert(i >= 0); #else eventsize = sizeof(struct sctp_event_subscribe); i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); OPENSSL_assert(i >= 0); event.sctp_sender_dry_event = 0; i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, sizeof(struct sctp_event_subscribe)); OPENSSL_assert(i >= 0); #endif } #ifdef SCTP_AUTHENTICATION_EVENT if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) dgram_sctp_handle_auth_free_key_event(b, snp); #endif if (data->handle_notifications != NULL) data->handle_notifications(b, data->notification_context, (void*) out); memset(out, 0, outl); } else ret += n; } while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) && (ret < outl)); if (ret > 0 && !(msg.msg_flags & MSG_EOR)) { /* Partial message read, this should never happen! */ /* The buffer was too small, this means the peer sent * a message that was larger than allowed. */ if (ret == outl) return -1; /* Test if socket buffer can handle max record * size (2^14 + 2048 + 13) */ optlen = (socklen_t) sizeof(int); ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen); OPENSSL_assert(ret >= 0); OPENSSL_assert(optval >= 18445); /* Test if SCTP doesn't partially deliver below * max record size (2^14 + 2048 + 13) */ optlen = (socklen_t) sizeof(int); ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, &optlen); OPENSSL_assert(ret >= 0); OPENSSL_assert(optval >= 18445); /* Partially delivered notification??? Probably a bug.... */ OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION)); /* Everything seems ok till now, so it's most likely * a message dropped by PR-SCTP. */ memset(out, 0, outl); BIO_set_retry_read(b); return -1; } BIO_clear_retry_flags(b); if (ret < 0) { if (BIO_dgram_should_retry(ret)) { BIO_set_retry_read(b); data->_errno = get_last_socket_error(); } } /* Test if peer uses SCTP-AUTH before continuing */ if (!data->peer_auth_tested) { int ii, auth_data = 0, auth_forward = 0; unsigned char *p; struct sctp_authchunks *authchunks; optlen = (socklen_t)(sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); authchunks = OPENSSL_malloc(optlen); memset(authchunks, 0, optlen); ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, authchunks, &optlen); OPENSSL_assert(ii >= 0); for (p = (unsigned char*) authchunks->gauth_chunks; p < (unsigned char*) authchunks + optlen; p += sizeof(uint8_t)) { if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) auth_data = 1; if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) auth_forward = 1; } OPENSSL_free(authchunks); if (!auth_data || !auth_forward) { BIOerr(BIO_F_DGRAM_SCTP_READ,BIO_R_CONNECT_ERROR); return -1; } data->peer_auth_tested = 1; } } return(ret); }