X-Git-Url: http://dolda2000.com/gitweb/?a=blobdiff_plain;f=daemon%2Fnet.c;h=2a8fdefe304015411ad4d5982a569e90dee59bda;hb=c26de38e9fc0ceb4f51af1085da37db42f4c4411;hp=4fee86ce9f043c4d399383acf297eea6e49f33e8;hpb=4b939ad5aed6dc597346da3f45ce61832133abe3;p=doldaconnect.git diff --git a/daemon/net.c b/daemon/net.c index 4fee86c..2a8fdef 100644 --- a/daemon/net.c +++ b/daemon/net.c @@ -94,6 +94,8 @@ int getpublicaddr(int af, struct sockaddr **addr, socklen_t *lenbuf) flog(LOG_ERR, "could not convert net.publicif into local charset: %s", strerror(errno)); return(-1); } + if(!strcmp(pif, "")) + return(1); if((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) return(-1); conf.ifc_buf = smalloc(conf.ifc_len = 65536); @@ -107,32 +109,25 @@ int getpublicaddr(int af, struct sockaddr **addr, socklen_t *lenbuf) ipv4 = NULL; for(ifr = conf.ifc_ifcu.ifcu_req; (void *)ifr < bufend; ifr++) { + if(strcmp(ifr->ifr_name, pif)) + continue; memset(&req, 0, sizeof(req)); memcpy(req.ifr_name, ifr->ifr_name, sizeof(ifr->ifr_name)); if(ioctl(sock, SIOCGIFFLAGS, &req) < 0) + break; + if(!(req.ifr_flags & IFF_UP)) { - free(conf.ifc_buf); - close(sock); - return(-1); + flog(LOG_WARNING, "public interface is down"); + break; } - if(!(req.ifr_flags & IFF_UP)) - continue; - if(ifr->ifr_addr.sa_family == AF_INET) + if(ifr->ifr_addr.sa_family != AF_INET) { - if(ntohl(((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr) == 0x7f000001) - continue; - if(ipv4 == NULL) - { - ipv4 = smalloc(sizeof(*ipv4)); - memcpy(ipv4, &ifr->ifr_addr, sizeof(ifr->ifr_addr)); - } else { - free(ipv4); - free(conf.ifc_buf); - flog(LOG_WARNING, "could not locate an unambiguous interface for determining your public IP address - set net.publicif"); - errno = ENFILE; /* XXX: There's no appropriate one for this... */ - return(-1); - } + flog(LOG_WARNING, "address of the public interface is not AF_INET"); + break; } + ipv4 = smalloc(sizeof(*ipv4)); + memcpy(ipv4, &ifr->ifr_addr, sizeof(ifr->ifr_addr)); + break; } free(conf.ifc_buf); close(sock); @@ -145,8 +140,7 @@ int getpublicaddr(int af, struct sockaddr **addr, socklen_t *lenbuf) errno = ENETDOWN; return(-1); } - errno = EPFNOSUPPORT; - return(-1); + return(1); } static struct socket *newsock(int type) @@ -259,12 +253,14 @@ void putsock(struct socket *sk) { sk->outbuf.d.f = buf->next; free(buf->data); + free(buf->addr); free(buf); } while((buf = sk->inbuf.d.f) != NULL) { sk->inbuf.d.f = buf->next; free(buf->data); + free(buf->addr); free(buf); } break; @@ -592,12 +588,6 @@ struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, v errno = EOPNOTSUPP; return(NULL); } - /* I don't know if this is actually correct (it probably isn't), - * but since, at on least Linux systems, PF_* are specifically - * #define'd to their AF_* counterparts, it allows for a severely - * smoother implementation. If it breaks something on your - * platform, please tell me so. - */ if(confgetint("net", "mode") == 0) return(netcslistenlocal(type, name, namelen, func, data)); errno = EOPNOTSUPP; @@ -714,7 +704,8 @@ struct socket *netcsconn(struct sockaddr *addr, socklen_t addrlen, void (*func)( int pollsocks(int timeout) { - int i, num, ret, retlen; + int i, num, ret; + socklen_t retlen; int newfd; struct pollfd *pfds; struct socket *sk, *next, *newsk; @@ -1043,7 +1034,7 @@ int sockgetlocalname(struct socket *sk, struct sockaddr **namebuf, socklen_t *le len = sizeof(name); if(getsockname(sk->fd, (struct sockaddr *)&name, &len) < 0) { - flog(LOG_ERR, "BUG: alive socket with dead fd in sockgetlocalname"); + flog(LOG_ERR, "BUG: alive socket with dead fd in sockgetlocalname (%s)", strerror(errno)); return(-1); } *namebuf = memcpy(smalloc(len), &name, len); @@ -1051,40 +1042,68 @@ int sockgetlocalname(struct socket *sk, struct sockaddr **namebuf, socklen_t *le return(0); } +static void sethostaddr(struct sockaddr *dst, struct sockaddr *src) +{ + if(dst->sa_family != src->sa_family) + { + flog(LOG_ERR, "BUG: non-matching socket families in sethostaddr (%i -> %i)", src->sa_family, dst->sa_family); + return; + } + switch(src->sa_family) + { + case AF_INET: + ((struct sockaddr_in *)dst)->sin_addr = ((struct sockaddr_in *)src)->sin_addr; + break; + case AF_INET6: + ((struct sockaddr_in6 *)dst)->sin6_addr = ((struct sockaddr_in6 *)src)->sin6_addr; + break; + default: + flog(LOG_WARNING, "sethostaddr unimplemented for family %i", src->sa_family); + break; + } +} + +static int makepublic(struct sockaddr *addr) +{ + int ret; + socklen_t plen; + struct sockaddr *pname; + + if((ret = getpublicaddr(addr->sa_family, &pname, &plen)) < 0) + { + flog(LOG_ERR, "could not get public address: %s", strerror(errno)); + return(-1); + } + if(ret) + return(0); + sethostaddr(addr, pname); + free(pname); + return(0); +} + int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf) { socklen_t len; - struct sockaddr_storage name; - struct sockaddr_in *ipv4; - struct sockaddr *pname; - socklen_t pnamelen; + struct sockaddr *name; switch(confgetint("net", "mode")) { case 0: *namebuf = NULL; if((sk->state == SOCK_STL) || (sk->fd < 0)) - return(-1); - len = sizeof(name); - if(getsockname(sk->fd, (struct sockaddr *)&name, &len) < 0) { - flog(LOG_ERR, "BUG: alive socket with dead fd in sockgetremotename"); + errno = EBADF; return(-1); } - if(name.ss_family == AF_INET) + if(!sockgetlocalname(sk, &name, &len)) { - ipv4 = (struct sockaddr_in *)&name; - if(getpublicaddr(AF_INET, &pname, &pnamelen) < 0) - { - flog(LOG_WARNING, "could not determine public IP address - strange things may happen"); - return(-1); - } - ipv4->sin_addr.s_addr = ((struct sockaddr_in *)pname)->sin_addr.s_addr; - free(pname); + *namebuf = name; + *lenbuf = len; + makepublic(name); + return(0); } - *namebuf = memcpy(smalloc(len), &name, len); - *lenbuf = len; - return(0); + flog(LOG_ERR, "could not get remotely accessible name by any means"); + return(-1); case 1: errno = EOPNOTSUPP; return(-1); @@ -1095,6 +1114,29 @@ int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *l } } +int sockgetremotename2(struct socket *sk, struct socket *sk2, struct sockaddr **namebuf, socklen_t *lenbuf) +{ + struct sockaddr *name1, *name2; + socklen_t len1, len2; + + if(sk->family != sk2->family) + { + flog(LOG_ERR, "using sockgetremotename2 with sockets of differing family: %i %i", sk->family, sk2->family); + return(-1); + } + if(sockgetremotename(sk, &name1, &len1)) + return(-1); + if(sockgetremotename(sk2, &name2, &len2)) { + free(name1); + return(-1); + } + sethostaddr(name1, name2); + free(name2); + *namebuf = name1; + *lenbuf = len1; + return(0); +} + int addreq(struct sockaddr *x, struct sockaddr *y) { struct sockaddr_un *u1, *u2; @@ -1118,6 +1160,7 @@ int addreq(struct sockaddr *x, struct sockaddr *y) if(n1->sin_addr.s_addr != n2->sin_addr.s_addr) return(0); break; +#ifdef HAVE_IPV6 case AF_INET6: s1 = (struct sockaddr_in6 *)x; s2 = (struct sockaddr_in6 *)y; if(s1->sin6_port != s2->sin6_port) @@ -1125,6 +1168,7 @@ int addreq(struct sockaddr *x, struct sockaddr *y) if(memcmp(s1->sin6_addr.s6_addr, s2->sin6_addr.s6_addr, sizeof(s1->sin6_addr.s6_addr))) return(0); break; +#endif } return(1); }