static int dup_internal(const struct socket_info *si_oldd, int fd) { struct socket_info *si_newd; si_newd = (struct socket_info *)calloc(1, sizeof(struct socket_info)); si_newd->fd = fd; si_newd->family = si_oldd->family; si_newd->type = si_oldd->type; si_newd->protocol = si_oldd->protocol; si_newd->bound = si_oldd->bound; si_newd->bcast = si_oldd->bcast; if (si_oldd->path) si_newd->path = strdup(si_oldd->path); if (si_oldd->tmp_path) si_newd->tmp_path = strdup(si_oldd->tmp_path); si_newd->myname = sockaddr_dup(si_oldd->myname, si_oldd->myname_len); si_newd->myname_len = si_oldd->myname_len; si_newd->peername = sockaddr_dup(si_oldd->peername, si_oldd->peername_len); si_newd->peername_len = si_oldd->peername_len; si_newd->io = si_oldd->io; SWRAP_DLIST_ADD(sockets, si_newd); return fd; }
_PUBLIC_ int swrap_bind(int s, const struct sockaddr *myaddr, socklen_t addrlen) { int ret; struct sockaddr_un un_addr; struct socket_info *si = find_socket_info(s); if (!si) { return real_bind(s, myaddr, addrlen); } si->myname_len = addrlen; si->myname = sockaddr_dup(myaddr, addrlen); ret = sockaddr_convert_to_un(si, (const struct sockaddr *)myaddr, addrlen, &un_addr, 1, &si->bcast); if (ret == -1) return -1; unlink(un_addr.sun_path); ret = real_bind(s, (struct sockaddr *)&un_addr, sizeof(struct sockaddr_un)); if (ret == 0) { si->bound = 1; } return ret; }
static iodev_t * tcp_create(iodev_t *dev, struct sockaddr *local, struct sockaddr *remote, size_t bufsize, int with_linebuf) { // First create the basic (slightly larger) config iodev_cfg_t *cfg = iodev_alloc_cfg(sizeof(tcp_cfg_t), "tcp", tcp_free_cfg); iodev_t *tcp = iodev_init(dev, cfg, bufsize); // Initialise the extras tcp_cfg_t *tcfg = tcp_getcfg(tcp); tcfg->addrlen = local != NULL ? sockaddr_len(local) : remote != NULL ? sockaddr_len(remote) : 0; tcfg->local = sockaddr_dup(local); tcfg->remote = sockaddr_dup(remote); if (with_linebuf) dev->linebuf = stringstore_init(NULL); // default functions tcp->open = tcp_open; tcp->close = tcp_close; tcp->configure = tcp_configure; return tcp; }
_PUBLIC_ int swrap_connect(int s, const struct sockaddr *serv_addr, socklen_t addrlen) { int ret; struct sockaddr_un un_addr; struct socket_info *si = find_socket_info(s); if (!si) { return real_connect(s, serv_addr, addrlen); } if (si->bound == 0) { ret = swrap_auto_bind(si, serv_addr->sa_family); if (ret == -1) return -1; } if (si->family != serv_addr->sa_family) { errno = EINVAL; return -1; } ret = sockaddr_convert_to_un(si, (const struct sockaddr *)serv_addr, addrlen, &un_addr, 0, NULL); if (ret == -1) return -1; swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_SEND, NULL, 0); ret = real_connect(s, (struct sockaddr *)&un_addr, sizeof(struct sockaddr_un)); /* to give better errors */ if (ret == -1 && errno == ENOENT) { errno = EHOSTUNREACH; } if (ret == 0) { si->peername_len = addrlen; si->peername = sockaddr_dup(serv_addr, addrlen); si->connected = 1; swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_RECV, NULL, 0); swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_ACK, NULL, 0); } else { swrap_dump_packet(si, serv_addr, SWRAP_CONNECT_UNREACH, NULL, 0); } return ret; }
/* using sendto() or connect() on an unbound socket would give the recipient no way to reply, as unlike UDP and TCP, a unix domain socket can't auto-assign emphemeral port numbers, so we need to assign it here. Note: this might change the family from ipv6 to ipv4 */ static int swrap_auto_bind(struct socket_info *si, int family) { struct sockaddr_un un_addr; int i; char type; int ret; int port; struct stat st; if (autobind_start_init != 1) { autobind_start_init = 1; autobind_start = getpid(); autobind_start %= 50000; autobind_start += 10000; } un_addr.sun_family = AF_UNIX; switch (family) { case AF_INET: { struct sockaddr_in in; switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP; break; default: errno = ESOCKTNOSUPPORT; return -1; } memset(&in, 0, sizeof(in)); in.sin_family = AF_INET; in.sin_addr.s_addr = htonl(127<<24 | socket_wrapper_default_iface()); si->myname_len = sizeof(in); si->myname = sockaddr_dup(&in, si->myname_len); break; } #ifdef HAVE_IPV6 case AF_INET6: { struct sockaddr_in6 in6; if (si->family != family) { errno = ENETUNREACH; return -1; } switch (si->type) { case SOCK_STREAM: type = SOCKET_TYPE_CHAR_TCP_V6; break; case SOCK_DGRAM: type = SOCKET_TYPE_CHAR_UDP_V6; break; default: errno = ESOCKTNOSUPPORT; return -1; } memset(&in6, 0, sizeof(in6)); in6.sin6_family = AF_INET6; in6.sin6_addr = *swrap_ipv6(); in6.sin6_addr.s6_addr[15] = socket_wrapper_default_iface(); si->myname_len = sizeof(in6); si->myname = sockaddr_dup(&in6, si->myname_len); break; } #endif default: errno = ESOCKTNOSUPPORT; return -1; } if (autobind_start > 60000) { autobind_start = 10000; } for (i=0;i<1000;i++) { port = autobind_start + i; snprintf(un_addr.sun_path, sizeof(un_addr.sun_path), "%s/"SOCKET_FORMAT, socket_wrapper_dir(), type, socket_wrapper_default_iface(), port); if (stat(un_addr.sun_path, &st) == 0) continue; ret = real_bind(si->fd, (struct sockaddr *)&un_addr, sizeof(un_addr)); if (ret == -1) return ret; si->tmp_path = strdup(un_addr.sun_path); si->bound = 1; autobind_start = port + 1; break; } if (i == 1000) { errno = ENFILE; return -1; } si->family = family; set_port(si->family, port, si->myname); return 0; }
_PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen) { struct socket_info *parent_si, *child_si; int fd; struct sockaddr_un un_addr; socklen_t un_addrlen = sizeof(un_addr); struct sockaddr_un un_my_addr; socklen_t un_my_addrlen = sizeof(un_my_addr); struct sockaddr *my_addr; socklen_t my_addrlen, len; int ret; parent_si = find_socket_info(s); if (!parent_si) { return real_accept(s, addr, addrlen); } /* * assume out sockaddr have the same size as the in parent * socket family */ my_addrlen = socket_length(parent_si->family); if (my_addrlen <= 0) { errno = EINVAL; return -1; } my_addr = (struct sockaddr *)malloc(my_addrlen); if (my_addr == NULL) { return -1; } memset(&un_addr, 0, sizeof(un_addr)); memset(&un_my_addr, 0, sizeof(un_my_addr)); ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen); if (ret == -1) { free(my_addr); return ret; } fd = ret; len = my_addrlen; ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen, parent_si->family, my_addr, &len); if (ret == -1) { free(my_addr); close(fd); return ret; } child_si = (struct socket_info *)malloc(sizeof(struct socket_info)); memset(child_si, 0, sizeof(*child_si)); child_si->fd = fd; child_si->family = parent_si->family; child_si->type = parent_si->type; child_si->protocol = parent_si->protocol; child_si->bound = 1; child_si->is_server = 1; child_si->connected = 1; child_si->peername_len = len; child_si->peername = sockaddr_dup(my_addr, len); if (addr != NULL && addrlen != NULL) { *addrlen = len; if (*addrlen >= len) memcpy(addr, my_addr, len); *addrlen = 0; } ret = real_getsockname(fd, (struct sockaddr *)&un_my_addr, &un_my_addrlen); if (ret == -1) { free(child_si); close(fd); return ret; } len = my_addrlen; ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen, child_si->family, my_addr, &len); if (ret == -1) { free(child_si); free(my_addr); close(fd); return ret; } child_si->myname_len = len; child_si->myname = sockaddr_dup(my_addr, len); free(my_addr); SWRAP_DLIST_ADD(sockets, child_si); swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0); swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0); swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0); return fd; }
/**************************************************************************** this one is for AIX (tested on 4.2) ****************************************************************************/ int rep_getifaddrs(struct ifaddrs **ifap) { char buff[8192]; int fd, i; struct ifconf ifc; struct ifreq *ifr=NULL; struct ifaddrs *curif; struct ifaddrs *lastif = NULL; *ifap = NULL; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { close(fd); return -1; } ifr = ifc.ifc_req; /* Loop through interfaces */ i = ifc.ifc_len; while (i > 0) { unsigned int inc; inc = ifr->ifr_addr.sa_len; curif = calloc(1, sizeof(struct ifaddrs)); if (lastif == NULL) { *ifap = curif; } else { lastif->ifa_next = curif; } curif->ifa_name = strdup(ifr->ifr_name); curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr); curif->ifa_dstaddr = NULL; curif->ifa_data = NULL; curif->ifa_netmask = NULL; curif->ifa_next = NULL; if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { goto fail; } curif->ifa_flags = (unsigned short)ifr->ifr_flags; /* * The rest is requested only for AF_INET, for portability and * compatiblilty (see e.g. https://linux.die.net/man/7/netdevice) */ if (curif->ifa_addr->sa_family == AF_INET) { if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { goto fail; } curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr); if (curif->ifa_flags & IFF_BROADCAST) { if (ioctl(fd, SIOCGIFBRDADDR, ifr) != 0) { goto fail; } /* * OS/2 TCP/IP 4.21 is known to leave this field zeroed but return the * correct address. We assume that it's so if ioctl succeeds and family * matches what it should be. */ if (ifr->ifr_broadaddr.sa_len == 0 && ifr->ifr_broadaddr.sa_family == curif->ifa_addr->sa_family) { ifr->ifr_broadaddr.sa_len = sizeof(struct sockaddr_in); } curif->ifa_broadaddr = sockaddr_dup(&ifr->ifr_broadaddr); } else if (curif->ifa_flags & IFF_POINTOPOINT) { if (ioctl(fd, SIOCGIFDSTADDR, ifr) != 0) { goto fail; } /* * OS/2 TCP/IP 4.21 is known to leave this field zeroed but return the * correct address. We assume that it's so if ioctl succeeds and family * matches what it should be. */ if (ifr->ifr_dstaddr.sa_len == 0 && ifr->ifr_dstaddr.sa_family == curif->ifa_addr->sa_family) { ifr->ifr_dstaddr.sa_len = sizeof(struct sockaddr_in); } curif->ifa_dstaddr = sockaddr_dup(&ifr->ifr_dstaddr); } } lastif = curif; /* * Patch from Archie Cobbs ([email protected]). The * addresses in the SIOCGIFCONF interface list have a * minimum size. Usually this doesn't matter, but if * your machine has tunnel interfaces, etc. that have * a zero length "link address", this does matter. */ if (inc < sizeof(ifr->ifr_addr)) inc = sizeof(ifr->ifr_addr); inc += IFNAMSIZ; ifr = (struct ifreq*) (((char*) ifr) + inc); i -= inc; } close(fd); return 0; fail: close(fd); freeifaddrs(*ifap); return -1; }
int rep_getifaddrs(struct ifaddrs **ifap) { struct ifconf ifc; char buff[8192]; int fd, i, n; struct ifreq *ifr=NULL; struct in_addr ipaddr; struct in_addr nmask; char *iname; struct ifaddrs *curif; struct ifaddrs *lastif = NULL; *ifap = NULL; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { close(fd); return -1; } ifr = ifc.ifc_req; n = ifc.ifc_len / sizeof(struct ifreq); /* Loop through interfaces, looking for given IP address */ for (i=n-1; i>=0; i--) { if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) { freeifaddrs(*ifap); return -1; } curif = calloc(1, sizeof(struct ifaddrs)); curif->ifa_name = strdup(ifr[i].ifr_name); curif->ifa_flags = ifr[i].ifr_flags; curif->ifa_dstaddr = NULL; curif->ifa_data = NULL; curif->ifa_next = NULL; curif->ifa_addr = NULL; if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) { curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr); } curif->ifa_netmask = NULL; if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) { curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr); } if (lastif == NULL) { *ifap = curif; } else { lastif->ifa_next = curif; } lastif = curif; } close(fd); return 0; }
/**************************************************************************** this one is for AIX (tested on 4.2) ****************************************************************************/ int rep_getifaddrs(struct ifaddrs **ifap) { char buff[8192]; int fd, i; struct ifconf ifc; struct ifreq *ifr=NULL; struct in_addr ipaddr; struct in_addr nmask; char *iname; struct ifaddrs *curif; struct ifaddrs *lastif = NULL; *ifap = NULL; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { close(fd); return -1; } ifr = ifc.ifc_req; /* Loop through interfaces */ i = ifc.ifc_len; while (i > 0) { uint_t inc; inc = ifr->ifr_addr.sa_len; if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { freeaddrinfo(*ifap); return -1; } curif = calloc(1, sizeof(struct ifaddrs)); if (lastif == NULL) { *ifap = curif; } else { lastif->ifa_next = curif; } curif->ifa_name = strdup(ifr->ifr_name); curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr); curif->ifa_dstaddr = NULL; curif->ifa_data = NULL; curif->ifa_netmask = NULL; curif->ifa_next = NULL; if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { freeaddrinfo(*ifap); return -1; } curif->ifa_flags = ifr->ifr_flags; if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { freeaddrinfo(*ifap); return -1; } curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr); lastif = curif; next: /* * Patch from Archie Cobbs ([email protected]). The * addresses in the SIOCGIFCONF interface list have a * minimum size. Usually this doesn't matter, but if * your machine has tunnel interfaces, etc. that have * a zero length "link address", this does matter. */ if (inc < sizeof(ifr->ifr_addr)) inc = sizeof(ifr->ifr_addr); inc += IFNAMSIZ; ifr = (struct ifreq*) (((char*) ifr) + inc); i -= inc; } close(fd); return 0; }
/**************************************************************************** this should cover most of the streams based systems Thanks to [email protected] for several ideas in this code ****************************************************************************/ int rep_getifaddrs(struct ifaddrs **ifap) { struct ifreq ifreq; struct strioctl strioctl; char buff[8192]; int fd, i, n; struct ifreq *ifr=NULL; struct in_addr ipaddr; struct in_addr nmask; char *iname; struct ifaddrs *curif; struct ifaddrs *lastif = NULL; *ifap = NULL; if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { return -1; } strioctl.ic_cmd = SIOCGIFCONF; strioctl.ic_dp = buff; strioctl.ic_len = sizeof(buff); if (ioctl(fd, I_STR, &strioctl) < 0) { close(fd); return -1; } /* we can ignore the possible sizeof(int) here as the resulting number of interface structures won't change */ n = strioctl.ic_len / sizeof(struct ifreq); /* we will assume that the kernel returns the length as an int at the start of the buffer if the offered size is a multiple of the structure size plus an int */ if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) { ifr = (struct ifreq *)(buff + sizeof(int)); } else { ifr = (struct ifreq *)buff; } /* Loop through interfaces */ for (i = 0; i<n; i++) { ifreq = ifr[i]; curif = calloc(1, sizeof(struct ifaddrs)); if (lastif == NULL) { *ifap = curif; } else { lastif->ifa_next = curif; } strioctl.ic_cmd = SIOCGIFFLAGS; strioctl.ic_dp = (char *)&ifreq; strioctl.ic_len = sizeof(struct ifreq); if (ioctl(fd, I_STR, &strioctl) != 0) { freeifaddrs(*ifap); return -1; } curif->ifa_flags = ifreq.ifr_flags; strioctl.ic_cmd = SIOCGIFADDR; strioctl.ic_dp = (char *)&ifreq; strioctl.ic_len = sizeof(struct ifreq); if (ioctl(fd, I_STR, &strioctl) != 0) { freeifaddrs(*ifap); return -1; } curif->ifa_name = strdup(ifreq.ifr_name); curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr); curif->ifa_dstaddr = NULL; curif->ifa_data = NULL; curif->ifa_next = NULL; curif->ifa_netmask = NULL; strioctl.ic_cmd = SIOCGIFNETMASK; strioctl.ic_dp = (char *)&ifreq; strioctl.ic_len = sizeof(struct ifreq); if (ioctl(fd, I_STR, &strioctl) != 0) { freeifaddrs(*ifap); return -1; } curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr); lastif = curif; } close(fd); return 0; }
_PUBLIC_ int swrap_accept(int s, struct sockaddr *addr, socklen_t *addrlen) { struct socket_info *parent_si, *child_si; int fd; struct sockaddr_un un_addr; socklen_t un_addrlen = sizeof(un_addr); struct sockaddr_un un_my_addr; socklen_t un_my_addrlen = sizeof(un_my_addr); struct sockaddr my_addr; socklen_t my_addrlen = sizeof(my_addr); int ret; parent_si = find_socket_info(s); if (!parent_si) { return real_accept(s, addr, addrlen); } memset(&un_addr, 0, sizeof(un_addr)); memset(&un_my_addr, 0, sizeof(un_my_addr)); memset(&my_addr, 0, sizeof(my_addr)); ret = real_accept(s, (struct sockaddr *)&un_addr, &un_addrlen); if (ret == -1) return ret; fd = ret; ret = sockaddr_convert_from_un(parent_si, &un_addr, un_addrlen, parent_si->family, addr, addrlen); if (ret == -1) { close(fd); return ret; } child_si = (struct socket_info *)malloc(sizeof(struct socket_info)); memset(child_si, 0, sizeof(*child_si)); child_si->fd = fd; child_si->family = parent_si->family; child_si->type = parent_si->type; child_si->protocol = parent_si->protocol; child_si->bound = 1; child_si->is_server = 1; ret = real_getsockname(fd, (struct sockaddr *)&un_my_addr, &un_my_addrlen); if (ret == -1) { free(child_si); close(fd); return ret; } ret = sockaddr_convert_from_un(child_si, &un_my_addr, un_my_addrlen, child_si->family, &my_addr, &my_addrlen); if (ret == -1) { free(child_si); close(fd); return ret; } child_si->myname_len = my_addrlen; child_si->myname = sockaddr_dup(&my_addr, my_addrlen); child_si->peername_len = *addrlen; child_si->peername = sockaddr_dup(addr, *addrlen); SWRAP_DLIST_ADD(sockets, child_si); swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_SEND, NULL, 0); swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_RECV, NULL, 0); swrap_dump_packet(child_si, addr, SWRAP_ACCEPT_ACK, NULL, 0); return fd; }