diff options
Diffstat (limited to 'src/SocketAddr.c')
-rw-r--r-- | src/SocketAddr.c | 941 |
1 files changed, 941 insertions, 0 deletions
diff --git a/src/SocketAddr.c b/src/SocketAddr.c new file mode 100644 index 0000000..4322475 --- /dev/null +++ b/src/SocketAddr.c @@ -0,0 +1,941 @@ +/*--------------------------------------------------------------- + * Copyright (c) 1999,2000,2001,2002,2003 + * The Board of Trustees of the University of Illinois + * All Rights Reserved. + *--------------------------------------------------------------- + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software (Iperf) and associated + * documentation files (the "Software"), to deal in the Software + * without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit + * persons to whom the Software is furnished to do + * so, subject to the following conditions: + * + * + * Redistributions of source code must retain the above + * copyright notice, this list of conditions and + * the following disclaimers. + * + * + * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimers in the documentation and/or other materials + * provided with the distribution. + * + * + * Neither the names of the University of Illinois, NCSA, + * nor the names of its contributors may be used to endorse + * or promote products derived from this Software without + * specific prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE CONTIBUTORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * ________________________________________________________________ + * National Laboratory for Applied Network Research + * National Center for Supercomputing Applications + * University of Illinois at Urbana-Champaign + * http://www.ncsa.uiuc.edu + * ________________________________________________________________ + * + * Socket.cpp + * by Ajay Tirumala <tirumala@ncsa.uiuc.edu> + * and Mark Gates <mgates@nlanr.net> + * ------------------------------------------------------------------- */ + +#define HEADERS() + +#include "headers.h" + +#include "SocketAddr.h" +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* ------------------------------------------------------------------- + * Create a socket address. If inHostname is not null, resolve that + * address and fill it in. Fill in the port number. Use IPv6 ADDR_ANY + * if that is what is desired. + * ------------------------------------------------------------------- */ +void SockAddr_remoteAddr (struct thread_Settings *inSettings) { + if (SockAddr_isZeroAddress(&inSettings->peer) == 0) { + if (inSettings->mHost != NULL) { + SockAddr_setHostname(inSettings->mHost, &inSettings->peer, isIPV6(inSettings)); + if (inSettings->incrdstip) + SockAddr_incrAddress(&inSettings->peer, inSettings->incrdstip); + } else { +#if HAVE_IPV6 + if (isIPV6(inSettings)) { + ((struct sockaddr*)&inSettings->peer)->sa_family = AF_INET6; + } else { + ((struct sockaddr*)&inSettings->peer)->sa_family = AF_INET; + } + } + if (SockAddr_isIPv6(&inSettings->peer)) { + inSettings->size_peer = sizeof(struct sockaddr_in6); + } else { + inSettings->size_peer = sizeof(struct sockaddr_in); + } +#else + } + ((struct sockaddr*)&inSettings->peer)->sa_family = AF_INET; + inSettings->size_peer = sizeof(struct sockaddr_in); +#endif + SockAddr_setPort(&inSettings->peer, inSettings->mPort); + } +} +// end SocketAddr + +void SockAddr_localAddr (struct thread_Settings *inSettings) { + SockAddr_zeroAddress(&inSettings->local); + + if (inSettings->mLocalhost != NULL) { + SockAddr_setHostname(inSettings->mLocalhost, &inSettings->local, + isIPV6(inSettings)); + if (inSettings->incrsrcip) + SockAddr_incrAddress(&inSettings->local, inSettings->incrsrcip); + + } else { +#if HAVE_IPV6 + if (isIPV6(inSettings)) { + ((struct sockaddr*)&inSettings->local)->sa_family = AF_INET6; + } else { + ((struct sockaddr*)&inSettings->local)->sa_family = AF_INET; + } + } + + if (SockAddr_isIPv6(&inSettings->local)) { + inSettings->size_local = sizeof(struct sockaddr_in6); + } else { + inSettings->size_local = sizeof(struct sockaddr_in); + } +#else + ((struct sockaddr*)&inSettings->local)->sa_family = AF_INET; + } + inSettings->size_local = sizeof(struct sockaddr_in); +#endif + /* + * This section handles the *local* port binding (which is messy) + * Quintuple is Proto:LocalIP:LocalPort:DstIP:DstPort + * + * There are three threads being Client, Listener and Server + * mPort comes from the -p command (which defaults to 5001) + * mLocalhost indicates -B set requesting a local binding + * mBindPort comes from -B IP:<port> (where port defaults to 0) + * Multicast IP address, e.g. 239.1.1.1, is set per a -B + * Zero will cause the OS to auto assign a LocalPort + * For iperf -s; Windows uses listener thread, *nix a server thread + * (so, effectively, Listener and Server threads are the same) + * Client threads support either auto assignment (default) or + * user specified (via -B) + */ + if (inSettings->mLocalhost == NULL) { + if (inSettings->mThreadMode == kMode_Client) { + /* + * Client thread, -p and no -B, + * OS will auto assign a free local port + */ + SockAddr_setPortAny (&inSettings->local); + } else { + /* Server or Listener thread, -p and no -B */ + SockAddr_setPort(&inSettings->local, inSettings->mPort); + } + } else { + // -B was set + if (inSettings->mThreadMode == kMode_Client) { + /* Client thread */ + if (inSettings->mBindPort) { + /* + * User specified port so use it + */ +#if HAVE_DECL_SO_REUSEPORT + int boolean = 1; + Socklen_t len = sizeof(boolean); + setsockopt(inSettings->mSock, SOL_SOCKET, SO_REUSEPORT, (char*) &boolean, len); +#endif + SockAddr_setPort(&inSettings->local, (inSettings->mBindPort + inSettings->incrsrcport)); + } else { + /* + * No user specified port, let OS assign a free one + */ + SockAddr_setPortAny (&inSettings->local); + } + } else { + /* + * Server or Listener thread, both always use -p port + * any -B port will be ignored + */ + SockAddr_setPort(&inSettings->local, inSettings->mPort); + } + } +} +// end SocketAddr + +/* ------------------------------------------------------------------- + * Resolve the hostname address and fill it in. + * ------------------------------------------------------------------- */ +void SockAddr_setHostname (const char* inHostname, iperf_sockaddr *inSockAddr, int isIPv6) { + // ..I think this works for both ipv6 & ipv4... we'll see + bool found = false; + int ret_ga; + struct addrinfo *res = NULL, *itr; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + if (!isIPv6) { + hints.ai_family = AF_INET; + ret_ga = getaddrinfo(inHostname, NULL, &hints, &res); + if (ret_ga == 0) { + if (res && res->ai_addr) { + itr = res; + // Now search for a IPv4 Address + while (itr != NULL) { + if (itr->ai_family == AF_INET) { + memcpy(inSockAddr, (itr->ai_addr), (itr->ai_addrlen)); + freeaddrinfo(res); + found = true; + break; + } else { + itr = itr->ai_next; + } + } + } + } + } +#if HAVE_IPV6 + if (!found) { + hints.ai_family = AF_INET6; + ret_ga = getaddrinfo(inHostname, NULL, &hints, &res); + if (ret_ga == 0) { + if (res && res->ai_addr) { + // Now search for a IPv6 Address + itr = res; + while (itr != NULL) { + if (itr->ai_family == AF_INET6) { + memcpy(inSockAddr, (itr->ai_addr), (itr->ai_addrlen)); + freeaddrinfo(res); + found = true; + break; + } else { + itr = itr->ai_next; + } + } + } + } + } +#endif // IPV6 + // getaddrinfo didn't find an address, fallback to gethostbyname for v4 + if (!found && !isIPv6) { + // first try just converting dotted decimal + // on Windows gethostbyname doesn't understand dotted decimal + struct sockaddr_in *sockaddr = (struct sockaddr_in *)inSockAddr; + int rc = inet_pton(AF_INET, inHostname, &sockaddr->sin_addr); + sockaddr->sin_family = AF_INET; + if (rc == 0) { + struct hostent *hostP = gethostbyname(inHostname); + if (hostP == NULL) { + /* this is the same as herror() but works on more systems */ + const char* format; + switch (h_errno) { + case HOST_NOT_FOUND: + format = "%s: Unknown host\n"; + break; + case NO_ADDRESS: + format = "%s: No address associated with name\n"; + break; + case NO_RECOVERY: + format = "%s: Unknown server error\n"; + break; + case TRY_AGAIN: + format = "%s: Host name lookup failure\n"; + break; + default: + format = "%s: Unknown resolver error\n"; + break; + } + fprintf(stderr, format, inHostname); + exit(1); + return; // TODO throw + } + found = true; + memcpy(&sockaddr->sin_addr, *(hostP->h_addr_list), (hostP->h_length)); + } + } + if (!found) { + fprintf(stderr, "ERROR: failed to find an ip address for host '%s'\n", inHostname); + exit(1); + } +} +// end setHostname + +/* ------------------------------------------------------------------- + * Copy the IP address into the string. + * ------------------------------------------------------------------- */ +void SockAddr_getHostAddress (iperf_sockaddr *inSockAddr, char* outAddress, + size_t len) { + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET) { + inet_ntop(AF_INET, &(((struct sockaddr_in*) inSockAddr)->sin_addr), + outAddress, len); + } +#if HAVE_IPV6 + else { + inet_ntop(AF_INET6, &(((struct sockaddr_in6*) inSockAddr)->sin6_addr), + outAddress, len); + } +#endif +} +// end getHostAddress + +/* ------------------------------------------------------------------- + * Set the address to any (generally all zeros). + * ------------------------------------------------------------------- */ +void SockAddr_setAddressAny (iperf_sockaddr *inSockAddr) { + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET) + memset(&(((struct sockaddr_in*) inSockAddr)->sin_addr), 0, + sizeof(struct in_addr)); +#if HAVE_IPV6 + else + memset(&(((struct sockaddr_in6*) inSockAddr)->sin6_addr), 0, + sizeof(struct in6_addr)); +#endif +} +// end setAddressAny + +/* ------------------------------------------------------------------- + * Incr the address by value + * ------------------------------------------------------------------- */ +void SockAddr_incrAddress (iperf_sockaddr *inSockAddr, int value) { + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET) + ((struct sockaddr_in *)inSockAddr)->sin_addr.s_addr += htonl(value); +#if HAVE_IPV6 + else { + uint32_t *lower = (uint32_t *)&((struct sockaddr_in6 *)inSockAddr)->sin6_addr.s6_addr[12]; + *lower += htonl(value); + } +#endif +} +// end setAddressAny + + +/* ------------------------------------------------------------------- + * Set the port to the given port. Handles the byte swapping. + * ------------------------------------------------------------------- */ +void SockAddr_setPort (iperf_sockaddr *inSockAddr, unsigned short inPort) { + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET) + ((struct sockaddr_in*) inSockAddr)->sin_port = htons(inPort); +#if HAVE_IPV6 + else + ((struct sockaddr_in6*) inSockAddr)->sin6_port = htons(inPort); +#endif + +} +// end setPort + +/* ------------------------------------------------------------------- + * Set the port to zero, which lets the OS pick the port. + * ------------------------------------------------------------------- */ +void SockAddr_setPortAny (iperf_sockaddr *inSockAddr) { + SockAddr_setPort(inSockAddr, 0); +} +// end setPortAny + +/* ------------------------------------------------------------------- + * Return the port. Handles the byte swapping. + * ------------------------------------------------------------------- */ +unsigned short SockAddr_getPort (iperf_sockaddr *inSockAddr) { + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET) + return ntohs(((struct sockaddr_in*) inSockAddr)->sin_port); +#if HAVE_IPV6 + else + return ntohs(((struct sockaddr_in6*) inSockAddr)->sin6_port); +#endif + return 0; + +} +// end getPort + +/* ------------------------------------------------------------------- + * Return the IPv4 Internet Address from the sockaddr_in structure + * ------------------------------------------------------------------- */ +struct in_addr* SockAddr_get_in_addr (iperf_sockaddr *inSockAddr) { + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET) + return &(((struct sockaddr_in*) inSockAddr)->sin_addr); + + fprintf(stderr, "FATAL: get_in_addr called on IPv6 address\n"); + return NULL; +} + +/* ------------------------------------------------------------------- + * Return the IPv6 Internet Address from the sockaddr_in6 structure + * ------------------------------------------------------------------- */ +#if HAVE_IPV6 +struct in6_addr* SockAddr_get_in6_addr (iperf_sockaddr *inSockAddr) { + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET6) + return &(((struct sockaddr_in6*) inSockAddr)->sin6_addr); + + fprintf(stderr, "FATAL: get_in6_addr called on IPv4 address\n"); + return NULL; +} +#endif + + +/* ------------------------------------------------------------------- + * Return the size of the appropriate address structure. + * ------------------------------------------------------------------- */ +Socklen_t SockAddr_get_sizeof_sockaddr (iperf_sockaddr *inSockAddr) { +#if HAVE_IPV6 + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET6) { + return(sizeof(struct sockaddr_in6)); + } +#endif + return(sizeof(struct sockaddr_in)); +} +// end get_sizeof_sockaddr + + +/* ------------------------------------------------------------------- + * Return if IPv6 socket + * ------------------------------------------------------------------- */ +int SockAddr_isIPv6 (iperf_sockaddr *inSockAddr) { +#if HAVE_IPV6 + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET6) { + return 1; + } +#endif + return 0; +} +// end get_sizeof_sockaddr + +/* ------------------------------------------------------------------- + * Return true if the address is multicast ip address. + * ------------------------------------------------------------------- */ +int SockAddr_isMulticast (iperf_sockaddr *inSockAddr) { +#if HAVE_IPV6 + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET6) { + return(IN6_IS_ADDR_MULTICAST(&(((struct sockaddr_in6*) inSockAddr)->sin6_addr))); + } else +#endif + { + +#ifdef IN_MULTICAST + // 224.0.0.0 to 239.255.255.255 (e0.00.00.00 to ef.ff.ff.ff) + // convert from network to host byte order + uint32_t maddr = ntohl((uint32_t)(((struct sockaddr_in*) inSockAddr)->sin_addr.s_addr)); + return (IN_MULTICAST(maddr)); +#else + const unsigned long kClassD_Mask = 0xf0000000L; + const unsigned long kMulticast = 0xe0000000L; + return((((ntohl(((struct sockaddr_in*) inSockAddr)->sin_addr.s_addr)) & kClassD_Mask) == kMulticast)); +#endif + } +} +// end isMulticast + +/* ------------------------------------------------------------------- + * Return true if the address is multicast ip address. + * ------------------------------------------------------------------- */ +int SockAddr_isLinklocal (iperf_sockaddr *inSockAddr) { +#if HAVE_IPV6 + if (((struct sockaddr*)inSockAddr)->sa_family == AF_INET6) { + return(IN6_IS_ADDR_LINKLOCAL(&(((struct sockaddr_in6*) inSockAddr)->sin6_addr))); + } else +#endif + { + return 0; + } +} + +/* ------------------------------------------------------------------- + * Zero out the address structure. + * ------------------------------------------------------------------- */ +void SockAddr_zeroAddress (iperf_sockaddr *inSockAddr) { + memset(inSockAddr, 0, sizeof(iperf_sockaddr)); +} + +int SockAddr_isZeroAddress (iperf_sockaddr *inSockAddr) { + iperf_sockaddr zeroSockAddr; + memset(&zeroSockAddr, 0, sizeof(iperf_sockaddr)); + return(memcmp((void *)inSockAddr, (void *)&zeroSockAddr, sizeof(iperf_sockaddr))); +} + +/* ------------------------------------------------------------------- + * Compare two sockaddrs and return true if they are equal + * ------------------------------------------------------------------- */ +int SockAddr_are_Equal (iperf_sockaddr *first, iperf_sockaddr *second) { + if (((struct sockaddr*)first)->sa_family == AF_INET && ((struct sockaddr*)second)->sa_family == AF_INET) { + // compare IPv4 adresses + return(((long) ((struct sockaddr_in*)first)->sin_addr.s_addr == (long) ((struct sockaddr_in*)second)->sin_addr.s_addr) + && (((struct sockaddr_in*)first)->sin_port == ((struct sockaddr_in*)second)->sin_port)); + } +#if HAVE_IPV6 + if (((struct sockaddr*)first)->sa_family == AF_INET6 && ((struct sockaddr*)second)->sa_family == AF_INET6) { + // compare IPv6 addresses + return(!memcmp(((struct sockaddr_in6*)first)->sin6_addr.s6_addr, ((struct sockaddr_in6*)second)->sin6_addr.s6_addr, sizeof(struct in6_addr)) + && (((struct sockaddr_in6*)first)->sin6_port == ((struct sockaddr_in6*)second)->sin6_port)); + } +#endif + return 0; +} + +/* ------------------------------------------------------------------- + * Compare two sockaddrs and return true if the hosts are equal + * ------------------------------------------------------------------- */ +int SockAddr_Hostare_Equal (iperf_sockaddr* first, iperf_sockaddr *second) { + if (((struct sockaddr*)first)->sa_family == AF_INET && ((struct sockaddr*)second)->sa_family == AF_INET) { + // compare IPv4 adresses + return((long) ((struct sockaddr_in*)first)->sin_addr.s_addr == + (long) ((struct sockaddr_in*)second)->sin_addr.s_addr); + } +#if HAVE_IPV6 + if (((struct sockaddr*)first)->sa_family == AF_INET6 && ((struct sockaddr*)second)->sa_family == AF_INET6) { + // compare IPv6 addresses + return(!memcmp(((struct sockaddr_in6*)first)->sin6_addr.s6_addr, + ((struct sockaddr_in6*)second)->sin6_addr.s6_addr, sizeof(struct in6_addr))); + } +#endif + return 0; +} + +/* ------------------------------------------------------------------- + * Find the interface name of a connected socket (when not already set) + * Can be forced with -B <ip>%<name> (server), -c <ip>%<name> (client) + * Note that kernel maps, e.g. via routing tables, to the actual device + * so these can change. Assume they won't change during the life + * of a thread. + * + * Store (and cache) the results in the thread settings structure + * Return 0 if set, -1 if not + * ------------------------------------------------------------------- */ +int SockAddr_Ifrname (struct thread_Settings *inSettings) { +#ifdef HAVE_IFADDRS_H + if (inSettings->mIfrname == NULL) { + struct sockaddr_storage myaddr; + struct ifaddrs* ifaddr; + struct ifaddrs* ifa; + socklen_t addr_len; + addr_len = sizeof(struct sockaddr_storage); + getsockname(inSettings->mSock, (struct sockaddr*)&myaddr, &addr_len); + getifaddrs(&ifaddr); + + // look which interface contains the desired IP per getsockname() which sets myaddr + // When found, ifa->ifa_name contains the name of the interface (eth0, eth1, ppp0...) + if (myaddr.ss_family == AF_INET) { + // v4 socket family (supports v4 only) + struct sockaddr_in* addr = (struct sockaddr_in*)&myaddr; + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if ((ifa->ifa_addr) && (ifa->ifa_addr->sa_family == AF_INET)) { + struct sockaddr_in* inaddr = (struct sockaddr_in*)ifa->ifa_addr; + if ((inaddr->sin_addr.s_addr == addr->sin_addr.s_addr) && (ifa->ifa_name)) { + // Found v4 address in v4 addr family, copy it to thread settings structure + inSettings->mIfrname = calloc (strlen(ifa->ifa_name) + 1, sizeof(char)); + strcpy(inSettings->mIfrname, ifa->ifa_name); + break; + } + } + } + } else if (myaddr.ss_family == AF_INET6) { + // v6 socket family (supports both v4 and v6) + struct sockaddr_in6* addr = (struct sockaddr_in6*)&myaddr; + // Link local address are shared amongst all devices + // Try to pull the interface from the destination + if ((inSettings->mThreadMode == kMode_Client) && (IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr))) { + char *results; + char *copy = (char *)malloc(strlen(inSettings->mHost)+1); + strcpy(copy,(const char *)inSettings->mHost); + if (((results = strtok(copy, "%")) != NULL) && ((results = strtok(NULL, "%")) != NULL)) { + inSettings->mIfrname = calloc (strlen(results) + 1, sizeof(char)); + strcpy(inSettings->mIfrname, results); + } + free(copy); + } else if ((inSettings->mThreadMode == kMode_Server) && (IN6_IS_ADDR_V4MAPPED (&addr->sin6_addr))) { + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if ((ifa->ifa_addr) && (ifa->ifa_addr->sa_family == AF_INET)) { + struct sockaddr_in* inaddr = (struct sockaddr_in*)ifa->ifa_addr; + uint32_t v4; + memcpy(&v4, &addr->sin6_addr.s6_addr[12], 4); + if ((ifa->ifa_name) && (inaddr->sin_addr.s_addr == v4)) { + // Found v4 address in v4 addr family, copy it to thread settings structure + inSettings->mIfrname = calloc (strlen(ifa->ifa_name) + 1, sizeof(char)); + strcpy(inSettings->mIfrname, ifa->ifa_name); + break; + } + } + } + } else { + // Hunt the v6 interfaces + for (ifa = ifaddr; ifa != NULL; ifa = ifa->ifa_next) { + if ((ifa->ifa_addr) && (ifa->ifa_addr->sa_family == AF_INET6)) { + struct sockaddr_in6* inaddr = (struct sockaddr_in6*)ifa->ifa_addr; + if ((ifa->ifa_name) && (IN6_ARE_ADDR_EQUAL(&addr->sin6_addr, &inaddr->sin6_addr))) { + // Found v6 address in v6 addr family, copy it to thread settings structure + inSettings->mIfrname = calloc (strlen(ifa->ifa_name) + 1, sizeof(char)); + strcpy(inSettings->mIfrname, ifa->ifa_name); + break; + } + } + } + } + } + freeifaddrs(ifaddr); + } +#endif + return ((inSettings->mIfrname == NULL) ? -1 : 0); +} + + +#if defined(HAVE_LINUX_FILTER_H) && defined(HAVE_AF_PACKET) +int SockAddr_Drop_All_BPF (int sock) { + struct sock_filter udp_filter[] = { + { 0x6, 0, 0, 0x00000000 }, + }; + struct sock_fprog bpf = { + .len = (sizeof(udp_filter) / sizeof(struct sock_filter)), + .filter = udp_filter, + }; + return(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))); +} + +// +// [root@ryzen3950 iperf2-code]# tcpdump ip and udp dst port 5001 -e -dd -i any +// tcpdump: data link type LINUX_SLL2 +// { 0x28, 0, 0, 0x00000000 }, +// { 0x15, 0, 8, 0x00000800 }, +// { 0x30, 0, 0, 0x0000001d }, +// { 0x15, 0, 6, 0x00000011 }, +// { 0x28, 0, 0, 0x0000001a }, +// { 0x45, 4, 0, 0x00001fff }, +// { 0xb1, 0, 0, 0x00000014 }, +// { 0x48, 0, 0, 0x00000016 }, +// { 0x15, 0, 1, 0x00001389 }, +// { 0x6, 0, 0, 0x00040000 }, +// { 0x6, 0, 0, 0x00000000 }, + +// { 0x28, 0, 0, 0x00000014 }, +// { 0x45, 4, 0, 0x00001fff }, +// { 0xb1, 0, 0, 0x0000001e }, +// { 0x48, 0, 0, 0x00000010 }, +// { 0x15, 0, 1, 0x00001389 }, + + +int SockAddr_v4_Accept_BPF (int sock, uint16_t port) { + // tcpdump udp dst port 5001 -dd to get c code filter + // UDP port is the 5 and 13 bytecodes (5001 = 0x1389) + // see linux/filter.h + struct sock_filter udp_filter[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 8, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 6, 0x00000011 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 4, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x00000010 }, + { 0x15, 0, 1, 0x00001389 }, + { 0x6, 0, 0, 0x00040000 }, + { 0x6, 0, 0, 0x00000000 }, + }; + udp_filter[8].k = port; + struct sock_fprog bpf = { + .len = (sizeof(udp_filter) / sizeof(struct sock_filter)), + .filter = udp_filter, + }; + return(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))); +} + +//[root@ryzen3950 iperf2-code]# tcpdump udp dst port 5001 and dst host 1.1.1.1 -dd +//Warning: assuming Ethernet +//{ 0x28, 0, 0, 0x0000000c }, +//{ 0x15, 11, 0, 0x000086dd }, +//{ 0x15, 0, 10, 0x00000800 }, +//{ 0x30, 0, 0, 0x00000017 }, +//{ 0x15, 0, 8, 0x00000011 }, +//{ 0x28, 0, 0, 0x00000014 }, +//{ 0x45, 6, 0, 0x00001fff }, +//{ 0xb1, 0, 0, 0x0000000e }, +//{ 0x48, 0, 0, 0x00000010 }, +//{ 0x15, 0, 3, 0x00001389 }, +//{ 0x20, 0, 0, 0x0000001e }, +//{ 0x15, 0, 1, 0x01010101 }, +//{ 0x6, 0, 0, 0x00040000 }, +//{ 0x6, 0, 0, 0x00000000 }, +// +// BPF for TAP interaces with explicit v4 IP and UDP dst port +int SockAddr_Accept_V4_TAP_BPF (int sock, uint32_t dstip, uint16_t port) { + struct sock_filter udp_filter[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 11, 0, 0x000086dd }, + { 0x15, 0, 10, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 8, 0x00000011 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 6, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x00000010 }, + { 0x15, 0, 3, 0x00001389 }, + { 0x20, 0, 0, 0x0000001e }, + { 0x15, 0, 1, 0x00000000 }, + { 0x6, 0, 0, 0x00040000 }, + { 0x6, 0, 0, 0x00000000 }, + }; + udp_filter[12].k = htonl(dstip); + udp_filter[9].k = htons(port); + struct sock_fprog bpf = { + .len = (sizeof(udp_filter) / sizeof(struct sock_filter)), + .filter = udp_filter, + }; + return(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))); +} + +// Simulate the UDP connect for the AF_PACKET (or PF_PACKET) +// +int SockAddr_v4_Connect_BPF (int sock, uint32_t dstip, uint32_t srcip, uint16_t dstport, uint16_t srcport) { + // Use full quintuple, proto, src ip, dst ip, src port, dst port + // ip proto is already set per the PF_PACKET ETH_P_IP + // tcpdump udp and ip src 127.0.0.1 and ip dst 127.0.0.2 and src port 5001 and dst port 5002 -dd + // + // tcpdump udp and ip src 127.0.0.1 and ip dst 127.0.0.2 and src port 5001 and dst port 5002 -d + // (000) ldh [12] + // (001) jeq #0x86dd jt 17 jf 2 + // (002) jeq #0x800 jt 3 jf 17 + // (003) ldb [23] + // (004) jeq #0x11 jt 5 jf 17 + // (005) ld [26] + // (006) jeq #0x7f000001 jt 7 jf 17 + // (007) ld [30] + // (008) jeq #0x7f000002 jt 9 jf 17 + // (009) ldh [20] + // (010) jset #0x1fff jt 17 jf 11 + // (011) ldxb 4*([14]&0xf) + // (012) ldh [x + 14] + // (013) jeq #0x1389 jt 14 jf 17 + // (014) ldh [x + 16] + // (015) jeq #0x138a jt 16 jf 17 + // (016) ret #262144 + // (017) ret #0 + // + struct sock_filter udp_filter[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 15, 0, 0x000086dd }, + { 0x15, 0, 14, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 12, 0x00000011 }, + { 0x20, 0, 0, 0x0000001a }, + { 0x15, 0, 10, 0x7f000001 }, + { 0x20, 0, 0, 0x0000001e }, + { 0x15, 0, 8, 0x7f000002 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 6, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x0000000e }, + { 0x15, 0, 3, 0x00001389 }, + { 0x48, 0, 0, 0x00000010 }, + { 0x15, 0, 1, 0x0000138a }, + { 0x6, 0, 0, 0x00040000 }, + { 0x6, 0, 0, 0x00000000 }, + }; + udp_filter[6].k = htonl(srcip); + udp_filter[8].k = htonl(dstip); + udp_filter[13].k = htons(srcport); + udp_filter[15].k = htons(dstport); + struct sock_fprog bpf = { + .len = (sizeof(udp_filter) / sizeof(struct sock_filter)), + .filter = udp_filter, + }; + return(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))); +} +int SockAddr_v4_Connect_TAP_BPF (int sock, uint32_t dstip, uint32_t srcip, uint16_t dstport, uint16_t srcport) { + // [root@ryzen3950 iperf2-code]# tcpdump ip and src 127.0.0.1 and dst 127.0.0.2 and udp src port 5001 and dst port 5002 -d + // Warning: assuming Ethernet + // (000) ldh [12] + // (001) jeq #0x800 jt 2 jf 16 + // (002) ld [26] + // (003) jeq #0x7f000001 jt 4 jf 16 + // (004) ld [30] + // (005) jeq #0x7f000002 jt 6 jf 16 + // (006) ldb [23] + // (007) jeq #0x11 jt 8 jf 16 + // (008) ldh [20] + // (009) jset #0x1fff jt 16 jf 10 + // (010) ldxb 4*([14]&0xf) + // (011) ldh [x + 14] + // (012) jeq #0x1389 jt 13 jf 16 + // (013) ldh [x + 16] + // (014) jeq #0x138a jt 15 jf 16 + // (015) ret #262144 + // (016) ret #0 + // [root@ryzen3950 iperf2-code]# tcpdump ip and src 127.0.0.1 and dst 127.0.0.2 and udp src port 5001 and dst port 5002 -dd + // Warning: assuming Ethernet + struct sock_filter udp_filter[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 14, 0x00000800 }, + { 0x20, 0, 0, 0x0000001a }, + { 0x15, 0, 12, 0x7f000001 }, + { 0x20, 0, 0, 0x0000001e }, + { 0x15, 0, 10, 0x7f000002 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 8, 0x00000011 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 6, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x0000000e }, + { 0x15, 0, 3, 0x00001389 }, + { 0x48, 0, 0, 0x00000010 }, + { 0x15, 0, 1, 0x0000138a }, + { 0x6, 0, 0, 0x00040000 }, + { 0x6, 0, 0, 0x00000000 }, + }; + udp_filter[3].k = htonl(srcip); + udp_filter[5].k = htonl(dstip); + udp_filter[12].k = htons(srcport); + udp_filter[14].k = htons(dstport); + struct sock_fprog bpf = { + .len = (sizeof(udp_filter) / sizeof(struct sock_filter)), + .filter = udp_filter, + }; + return(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))); +} + +int SockAddr_v4_Connect_BPF_Drop (int sock, uint32_t dstip, uint32_t srcip, uint16_t dstport, uint16_t srcport) { + // Use full quintuple, proto, src ip, dst ip, src port, dst port + // ip proto is already set per the PF_PACKET ETH_P_IP + // tcpdump udp and ip src 127.0.0.1 and ip dst 127.0.0.2 and src port 5001 and dst port 5002 -dd + + struct sock_filter udp_filter[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 15, 0, 0x000086dd }, + { 0x15, 0, 14, 0x00000800 }, + { 0x30, 0, 0, 0x00000017 }, + { 0x15, 0, 12, 0x00000011 }, + { 0x20, 0, 0, 0x0000001a }, + { 0x15, 0, 10, 0x7f000001 }, + { 0x20, 0, 0, 0x0000001e }, + { 0x15, 0, 8, 0x7f000002 }, + { 0x28, 0, 0, 0x00000014 }, + { 0x45, 6, 0, 0x00001fff }, + { 0xb1, 0, 0, 0x0000000e }, + { 0x48, 0, 0, 0x0000000e }, + { 0x15, 0, 3, 0x00001389 }, + { 0x48, 0, 0, 0x00000010 }, + { 0x15, 0, 1, 0x0000138a }, + { 0x6, 0, 0, 0x00000000 }, + { 0x6, 0, 0, 0x00000000 }, + }; + udp_filter[6].k = htonl(srcip); + udp_filter[8].k = htonl(dstip); + udp_filter[13].k = htons(srcport); + udp_filter[15].k = htons(dstport); + struct sock_fprog bpf = { + .len = (sizeof(udp_filter) / sizeof(struct sock_filter)), + .filter = udp_filter, + }; + return(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))); +} +#if HAVE_IPV6 +// +// v6 Connected BPF, use 32 bit values +// +int SockAddr_v6_Connect_BPF (int sock, struct in6_addr *dst, struct in6_addr *src, uint16_t dstport, uint16_t srcport) { + // Use full quintuple, proto, src ip, dst ip, src port, dst port + // tcpdump udp and ip6 src fe80::428d:5cff:fe6a:2d85 and ip6 dst fe80::428d:5cff:fe6a:2d86 and src port 5001 and dst port 5002 -dd + // + //tcpdump udp and ip6 src fe80::428d:5cff:fe6a:2d85 and ip6 dst fe80::428d:5cff:fe6a:2d86 and src port 5001 and dst port 5002 -d + // (000) ldh [12] + // (001) jeq #0x86dd jt 2 jf 32 + // (002) ldb [20] + // (003) jeq #0x11 jt 7 jf 4 + // (004) jeq #0x2c jt 5 jf 32 + // (005) ldb [54] + // (006) jeq #0x11 jt 7 jf 32 + // (007) ld [22] + // (008) jeq #0xfe800000 jt 9 jf 32 + // (009) ld [26] + // (010) jeq #0x0 jt 11 jf 32 + // (011) ld [30] + // (012) jeq #0x428d5cff jt 13 jf 32 + // (013) ld [34] + // (014) jeq #0xfe6a2d85 jt 15 jf 32 + // (015) ld [38] + // (016) jeq #0xfe800000 jt 17 jf 32 + // (017) ld [42] + // (018) jeq #0x0 jt 19 jf 32 + // (019) ld [46] + // (020) jeq #0x428d5cff jt 21 jf 32 + // (021) ld [50] + // (022) jeq #0xfe6a2d86 jt 23 jf 32 + // (023) ldb [20] + // (024) jeq #0x84 jt 27 jf 25 + // (025) jeq #0x6 jt 27 jf 26 + // (026) jeq #0x11 jt 27 jf 32 + // (027) ldh [54] + // (028) jeq #0x1389 jt 29 jf 32 + // (029) ldh [56] + // (030) jeq #0x138a jt 31 jf 32 + // (031) ret #262144 + // (032) ret #0 + // + struct sock_filter udp_filter[] = { + { 0x28, 0, 0, 0x0000000c }, + { 0x15, 0, 30, 0x000086dd }, + { 0x30, 0, 0, 0x00000014 }, + { 0x15, 3, 0, 0x00000011 }, + { 0x15, 0, 27, 0x0000002c }, + { 0x30, 0, 0, 0x00000036 }, + { 0x15, 0, 25, 0x00000011 }, + { 0x20, 0, 0, 0x00000016 }, + { 0x15, 0, 23, 0xfe800000 }, + { 0x20, 0, 0, 0x0000001a }, + { 0x15, 0, 21, 0x00000000 }, + { 0x20, 0, 0, 0x0000001e }, + { 0x15, 0, 19, 0x428d5cff }, + { 0x20, 0, 0, 0x00000022 }, + { 0x15, 0, 17, 0xfe6a2d85 }, + { 0x20, 0, 0, 0x00000026 }, + { 0x15, 0, 15, 0xfe800000 }, + { 0x20, 0, 0, 0x0000002a }, + { 0x15, 0, 13, 0x00000000 }, + { 0x20, 0, 0, 0x0000002e }, + { 0x15, 0, 11, 0x428d5cff }, + { 0x20, 0, 0, 0x00000032 }, + { 0x15, 0, 9, 0xfe6a2d86 }, + { 0x30, 0, 0, 0x00000014 }, + { 0x15, 2, 0, 0x00000084 }, + { 0x15, 1, 0, 0x00000006 }, + { 0x15, 0, 5, 0x00000011 }, + { 0x28, 0, 0, 0x00000036 }, + { 0x15, 0, 3, 0x00001389 }, + { 0x28, 0, 0, 0x00000038 }, + { 0x15, 0, 1, 0x0000138a }, + { 0x6, 0, 0, 0x00040000 }, + { 0x6, 0, 0, 0x00000000 }, + }; + udp_filter[8].k = htonl((*src).s6_addr32[0]); + udp_filter[10].k = htonl((*src).s6_addr32[1]); + udp_filter[12].k = htonl((*src).s6_addr32[2]); + udp_filter[14].k = htonl((*src).s6_addr32[3]); + udp_filter[16].k = htonl((*dst).s6_addr32[0]); + udp_filter[18].k = htonl((*dst).s6_addr32[1]); + udp_filter[20].k = htonl((*dst).s6_addr32[2]); + udp_filter[22].k = htonl((*dst).s6_addr32[3]); + udp_filter[28].k = htons(srcport); + udp_filter[30].k = htons(dstport); + struct sock_fprog bpf = { + .len = (sizeof(udp_filter) / sizeof(struct sock_filter)), + .filter = udp_filter, + }; + return(setsockopt(sock, SOL_SOCKET, SO_ATTACH_FILTER, &bpf, sizeof(bpf))); +} +# endif // HAVE_V6 +#endif // HAVE_LINUX_FILTER + +#ifdef __cplusplus +} /* end extern "C" */ +#endif |