int fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd) { int i, start; struct sockaddr_storage src; socklen_t sizeof_src = sizeof(src); fr_packet_socket_t *ps; if (!pl) return 0; ps = NULL; i = start = SOCK2OFFSET(sockfd); do { if (pl->sockets[i].sockfd == -1) { ps = &pl->sockets[i]; start = i; break; } i = (i + 1) & SOCKOFFSET_MASK; } while (i != start); if (!ps) { return 0; } memset(ps, 0, sizeof(*ps)); ps->sockfd = sockfd; ps->offset = start; /* * Get address family, etc. first, so we know if we * need to do udpfromto. * * FIXME: udpfromto also does this, but it's not * a critical problem. */ memset(&src, 0, sizeof_src); if (getsockname(sockfd, (struct sockaddr *) &src, &sizeof_src) < 0) { return 0; } if (!fr_sockaddr2ipaddr(&src, sizeof_src, &ps->ipaddr, &ps->port)) { return 0; } /* * Grab IP addresses & ports from the sockaddr. */ if (src.ss_family == AF_INET) { if (ps->ipaddr.ipaddr.ip4addr.s_addr == INADDR_ANY) { ps->inaddr_any = 1; } #ifdef HAVE_STRUCT_SOCKADDR_IN6 } else if (src.ss_family == AF_INET6) { if (IN6_IS_ADDR_UNSPECIFIED(&ps->ipaddr.ipaddr.ip6addr)) { ps->inaddr_any = 1; } #endif } else { return 0; } pl->mask |= (1 << ps->offset); return 1; }
/* * Wrapper for recvfrom, which handles recvfromto, IPv6, and all * possible combinations. * * FIXME: This is copied from rad_recvfrom, with minor edits. */ static ssize_t vqp_recvfrom(int sockfd, uint8_t **pbuf, int flags, fr_ipaddr_t *src_ipaddr, uint16_t *src_port, fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port) { struct sockaddr_storage src; struct sockaddr_storage dst; socklen_t sizeof_src = sizeof(src); socklen_t sizeof_dst = sizeof(dst); ssize_t data_len; uint8_t header[4]; void *buf; size_t len; int port; memset(&src, 0, sizeof_src); memset(&dst, 0, sizeof_dst); /* * Get address family, etc. first, so we know if we * need to do udpfromto. * * FIXME: udpfromto also does this, but it's not * a critical problem. */ if (getsockname(sockfd, (struct sockaddr *)&dst, &sizeof_dst) < 0) return -1; /* * Read the length of the packet, from the packet. * This lets us allocate the buffer to use for * reading the rest of the packet. */ data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK, (struct sockaddr *)&src, &sizeof_src); if (data_len < 0) return -1; /* * Too little data is available, discard the packet. */ if (data_len < 4) { recvfrom(sockfd, header, sizeof(header), flags, (struct sockaddr *)&src, &sizeof_src); return 0; /* * Invalid version, packet type, or too many * attributes. Die. */ } else if ((header[0] != VQP_VERSION) || (header[1] < 1) || (header[1] > 4) || (header[3] > VQP_MAX_ATTRIBUTES)) { recvfrom(sockfd, header, sizeof(header), flags, (struct sockaddr *)&src, &sizeof_src); return 0; } else { /* we got 4 bytes of data. */ /* * We don't care about the contents for now... */ #if 0 /* * How many attributes are in the packet. */ len = header[3]; if ((header[1] == 1) || (header[1] == 3)) { if (len != VQP_MAX_ATTRIBUTES) { recvfrom(sockfd, header, sizeof(header), 0, (struct sockaddr *)&src, &sizeof_src); return 0; } /* * Maximum length we support. */ len = (12 * (4 + 4 + MAX_VMPS_LEN)); } else { if (len != 2) { recvfrom(sockfd, header, sizeof(header), 0, (struct sockaddr *)&src, &sizeof_src); return 0; } /* * Maximum length we support. */ len = (12 * (4 + 4 + MAX_VMPS_LEN)); } #endif } /* * For now, be generous. */ len = (12 * (4 + 4 + MAX_VMPS_LEN)); buf = malloc(len); if (!buf) return -1; /* * Receive the packet. The OS will discard any data in the * packet after "len" bytes. */ #ifdef WITH_UDPFROMTO if (dst.ss_family == AF_INET) { data_len = recvfromto(sockfd, buf, len, flags, (struct sockaddr *)&src, &sizeof_src, (struct sockaddr *)&dst, &sizeof_dst); } else #endif /* * No udpfromto, OR an IPv6 socket. Fail gracefully. */ data_len = recvfrom(sockfd, buf, len, flags, (struct sockaddr *)&src, &sizeof_src); if (data_len < 0) { free(buf); return data_len; } if (!fr_sockaddr2ipaddr(&src, sizeof_src, src_ipaddr, &port)) { free(buf); return -1; /* Unknown address family, Die Die Die! */ } *src_port = port; fr_sockaddr2ipaddr(&dst, sizeof_dst, dst_ipaddr, &port); *dst_port = port; /* * Different address families should never happen. */ if (src.ss_family != dst.ss_family) { free(buf); return -1; } /* * Tell the caller about the data */ *pbuf = buf; return data_len; }
bool fr_packet_list_socket_add(fr_packet_list_t *pl, int sockfd, int proto, fr_ipaddr_t *dst_ipaddr, int dst_port, void *ctx) { int i, start; struct sockaddr_storage src; socklen_t sizeof_src; fr_packet_socket_t *ps; if (!pl || !dst_ipaddr || (dst_ipaddr->af == AF_UNSPEC)) { fr_strerror_printf("Invalid argument"); return false; } if (pl->num_sockets >= MAX_SOCKETS) { fr_strerror_printf("Too many open sockets"); return false; } #ifndef WITH_TCP if (proto != IPPROTO_UDP) { fr_strerror_printf("only UDP is supported"); return false; } #endif ps = NULL; i = start = SOCK2OFFSET(sockfd); do { if (pl->sockets[i].sockfd == -1) { ps = &pl->sockets[i]; break; } i = (i + 1) & SOCKOFFSET_MASK; } while (i != start); if (!ps) { fr_strerror_printf("All socket entries are full"); return false; } memset(ps, 0, sizeof(*ps)); ps->ctx = ctx; #ifdef WITH_TCP ps->proto = proto; #endif /* * Get address family, etc. first, so we know if we * need to do udpfromto. * * FIXME: udpfromto also does this, but it's not * a critical problem. */ sizeof_src = sizeof(src); memset(&src, 0, sizeof_src); if (getsockname(sockfd, (struct sockaddr *) &src, &sizeof_src) < 0) { fr_strerror_printf("%s", fr_syserror(errno)); return false; } if (!fr_sockaddr2ipaddr(&src, sizeof_src, &ps->src_ipaddr, &ps->src_port)) { fr_strerror_printf("Failed to get IP"); return false; } ps->dst_ipaddr = *dst_ipaddr; ps->dst_port = dst_port; ps->src_any = fr_inaddr_any(&ps->src_ipaddr); if (ps->src_any < 0) return false; ps->dst_any = fr_inaddr_any(&ps->dst_ipaddr); if (ps->dst_any < 0) return false; /* * As the last step before returning. */ ps->sockfd = sockfd; pl->num_sockets++; /* * Populate the ID array with a random list of IDs. */ ps->ids_index = 0; for (i = 0; i < 256; i++) { ps->ids[fr_rand() & 0xff] = i; } return true; }