#include <netinet/in.h>
#include <netdb.h>
#include <sys/signal.h>
-#include <printf.h>
#ifdef HAVE_LINUX_SOCKIOS_H
#include <linux/sockios.h>
#endif
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);
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);
errno = ENETDOWN;
return(-1);
}
- errno = EPFNOSUPPORT;
- return(-1);
+ return(1);
}
static struct socket *newsock(int type)
return(ret);
}
-struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
-{
- struct socket *sk;
- int intbuf;
-
- if(confgetint("net", "mode") == 1)
- {
- 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)
- {
- if((sk = mksock(name->sa_family, type)) == NULL)
- return(NULL);
- sk->state = SOCK_LST;
- if(confgetint("net", "reuseaddr"))
- {
- intbuf = 1;
- setsockopt(sk->fd, SOL_SOCKET, SO_REUSEADDR, &intbuf, sizeof(intbuf));
- }
- if(bind(sk->fd, name, namelen) < 0)
- {
- putsock(sk);
- return(NULL);
- }
- if(listen(sk->fd, 16) < 0)
- {
- putsock(sk);
- return(NULL);
- }
- sk->acceptcb = func;
- sk->data = data;
- return(sk);
- }
- errno = EOPNOTSUPP;
- return(NULL);
-}
-
/*
* The difference between netcslisten() and netcslistenlocal() is that
* netcslistenlocal() always listens on the local host, instead of
return(sk);
}
+struct socket *netcslisten(int type, struct sockaddr *name, socklen_t namelen, void (*func)(struct socket *, struct socket *, void *), void *data)
+{
+ if(confgetint("net", "mode") == 1)
+ {
+ errno = EOPNOTSUPP;
+ return(NULL);
+ }
+ if(confgetint("net", "mode") == 0)
+ return(netcslistenlocal(type, name, namelen, func, data));
+ errno = EOPNOTSUPP;
+ return(NULL);
+}
+
+struct socket *netcstcplisten(int port, int local, void (*func)(struct socket *, struct socket *, void *), void *data)
+{
+ struct sockaddr_in addr;
+#ifdef HAVE_IPV6
+ struct sockaddr_in6 addr6;
+#endif
+ struct socket *(*csfunc)(int, struct sockaddr *, socklen_t, void (*)(struct socket *, struct socket *, void *), void *);
+ struct socket *ret;
+
+ if(local)
+ csfunc = netcslistenlocal;
+ else
+ csfunc = netcslisten;
+#ifdef HAVE_IPV6
+ memset(&addr6, 0, sizeof(addr6));
+ addr6.sin6_family = AF_INET6;
+ addr6.sin6_port = htons(port);
+ addr6.sin6_addr = in6addr_any;
+ if((ret = csfunc(SOCK_STREAM, (struct sockaddr *)&addr6, sizeof(addr6), func, data)) != NULL)
+ return(ret);
+ if((ret == NULL) && (errno != EAFNOSUPPORT))
+ return(NULL);
+#endif
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+ return(csfunc(SOCK_STREAM, (struct sockaddr *)&addr, sizeof(addr), func, data));
+}
+
struct socket *netcsdgram(struct sockaddr *name, socklen_t namelen)
{
struct socket *sk;
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);
int sockgetremotename(struct socket *sk, struct sockaddr **namebuf, socklen_t *lenbuf)
{
+ int ret;
socklen_t len;
- struct sockaddr_storage name;
- struct sockaddr_in *ipv4;
- struct sockaddr *pname;
- socklen_t pnamelen;
+ struct sockaddr *name;
switch(confgetint("net", "mode"))
{
*namebuf = NULL;
if((sk->state == SOCK_STL) || (sk->fd < 0))
return(-1);
- len = sizeof(name);
- if(getsockname(sk->fd, (struct sockaddr *)&name, &len) < 0)
+ if((ret = getpublicaddr(sk->family, &name, &len)) < 0)
{
- flog(LOG_ERR, "BUG: alive socket with dead fd in sockgetremotename");
+ flog(LOG_ERR, "could not get public address: %s", strerror(errno));
return(-1);
}
- if(name.ss_family == AF_INET)
+ if(ret == 0)
{
- 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;
+ return(0);
}
- *namebuf = memcpy(smalloc(len), &name, len);
- *lenbuf = len;
- return(0);
+ if(!sockgetlocalname(sk, &name, &len))
+ {
+ *namebuf = name;
+ *lenbuf = len;
+ return(0);
+ }
+ flog(LOG_ERR, "could not get remotely accessible name by any means");
+ return(-1);
case 1:
errno = EOPNOTSUPP;
return(-1);