Date: Thu, 10 Nov 2005 19:08:11 -0600 (CST) From: Craig Boston <craig@tobuj.gank.org> To: FreeBSD-gnats-submit@FreeBSD.org Subject: bin/88821: [PATCH] IPv6 support for ggate Message-ID: <20051111010811.1E7032D2D3@ion.gank.org> Resent-Message-ID: <200511110110.jAB1AGKu030956@freefall.freebsd.org>
index | next in thread | raw e-mail
>Number: 88821
>Category: bin
>Synopsis: [PATCH] IPv6 support for ggate
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-bugs
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: change-request
>Submitter-Id: current-users
>Arrival-Date: Fri Nov 11 01:10:16 GMT 2005
>Closed-Date:
>Last-Modified:
>Originator: Craig Boston
>Release: FreeBSD 6.0-STABLE i386
>Organization:
I wish I had some
>Environment:
System: FreeBSD hostname.gank.org 6.0-STABLE FreeBSD 6.0-STABLE #0: Sat Nov 5 20:59:05 CST 2005 root@hostname.gank.org:/compile/obj/compile/src/sys/HOSTNAME i386
>Description:
Adds full IPv6 support to ggated and complete address family
independence to ggatec.
>How-To-Repeat:
n/a
>Fix:
--- ggate_ipv6_2.patch begins here ---
diff -ruN ggate.orig/ggatec/ggatec.c ggate/ggatec/ggatec.c
--- ggate.orig/ggatec/ggatec.c Thu Nov 10 18:53:21 2005
+++ ggate/ggatec/ggatec.c Thu Nov 10 18:53:25 2005
@@ -50,6 +50,7 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <netdb.h>
#include <geom/gate/g_gate.h>
#include "ggate.h"
@@ -63,7 +64,7 @@
static unsigned flags = 0;
static int force = 0;
static unsigned queue_size = G_GATE_QUEUE_SIZE;
-static unsigned port = G_GATE_PORT;
+static const char *port = G_GATE_PORT_STR;
static off_t mediasize;
static unsigned sectorsize = 0;
static unsigned timeout = G_GATE_TIMEOUT;
@@ -244,37 +245,55 @@
struct g_gate_version ver;
struct g_gate_cinit cinit;
struct g_gate_sinit sinit;
- struct sockaddr_in serv;
+ struct addrinfo hints;
+ struct addrinfo *res, *p;
int sfd;
/*
* Do the network stuff.
*/
- bzero(&serv, sizeof(serv));
- serv.sin_family = AF_INET;
- serv.sin_addr.s_addr = g_gate_str2ip(host);
- if (serv.sin_addr.s_addr == INADDR_NONE) {
- g_gate_log(LOG_DEBUG, "Invalid IP/host name: %s.", host);
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ sfd = -1;
+ if (getaddrinfo(host, port, &hints, &res) != 0) {
+ g_gate_log(LOG_DEBUG, "Invalid IP/host name or port: %s (%s).",
+ host, port);
return (-1);
- }
- serv.sin_port = htons(port);
- sfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sfd == -1) {
- g_gate_log(LOG_DEBUG, "Cannot open socket: %s.",
- strerror(errno));
- return (-1);
- }
+ } else {
+ p = res;
+ while (p) {
+ sfd = socket(p->ai_family, p->ai_socktype, 0);
+ if (sfd == -1) {
+ g_gate_log(LOG_DEBUG, "Cannot open socket: %s.",
+ strerror(errno));
+ freeaddrinfo(res);
+ return (-1);
+ }
- g_gate_socket_settings(sfd);
+ g_gate_socket_settings(sfd);
- if (connect(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1) {
- g_gate_log(LOG_DEBUG, "Cannot connect to server: %s.",
- strerror(errno));
- close(sfd);
+ if (connect(sfd, p->ai_addr, p->ai_addrlen) == 0)
+ break;
+
+ /* Non-critical error, try next address */
+ g_gate_log(LOG_DEBUG, "Cannot connect to server: %s.",
+ strerror(errno));
+ close(sfd);
+ sfd = -1;
+
+ p = p->ai_next;
+ }
+ }
+ freeaddrinfo(res);
+
+ if (sfd == -1) {
+ g_gate_log(LOG_DEBUG, "Invalid IP/host name or port: %s (%s).",
+ host, port);
return (-1);
}
- g_gate_log(LOG_INFO, "Connected to the server: %s:%d.", host, port);
+ g_gate_log(LOG_INFO, "Connected to the server: %s (%s).", host, port);
/*
* Create and send version packet.
@@ -454,7 +473,7 @@
ggioc.gctl_maxcount = queue_size;
ggioc.gctl_timeout = timeout;
ggioc.gctl_unit = unit;
- snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s:%u %s", host,
+ snprintf(ggioc.gctl_info, sizeof(ggioc.gctl_info), "%s (%s) %s", host,
port, path);
g_gate_ioctl(G_GATE_CMD_CREATE, &ggioc);
if (unit == -1)
@@ -535,9 +554,7 @@
if (action != CREATE && action != RESCUE)
usage();
errno = 0;
- port = strtoul(optarg, NULL, 10);
- if (port == 0 && errno != 0)
- errx(EXIT_FAILURE, "Invalid port.");
+ port = optarg;
break;
case 'q':
if (action != CREATE)
diff -ruN ggate.orig/ggated/ggated.8 ggate/ggated/ggated.8
--- ggate.orig/ggated/ggated.8 Thu Nov 10 18:53:21 2005
+++ ggate/ggated/ggated.8 Thu Nov 10 18:53:25 2005
@@ -55,7 +55,10 @@
Available options:
.Bl -tag -width ".Ar exports\ file"
.It Fl a Ar address
-Specifies an IP address to bind to.
+Specifies an IP address to bind to. To bind to multiple addresses,
+specify each address with a separate
+.Fl a
+option.
.It Fl h
Print available options.
.It Fl n
@@ -74,7 +77,7 @@
Size of send buffer to use.
Default is 131072 (128kB).
.It Fl v
-Do not fork, run in foreground and print debug informations on standard
+Do not fork, run in foreground and print debug information on standard
output.
.It Ar "exports file"
An alternate location for the exports file.
@@ -82,9 +85,10 @@
.Pp
The format of an exports file is as follows:
.Bd -literal -offset indent
-1.2.3.4 RO /dev/acd0
-1.2.3.0/24 RW /tmp/test.img
-hostname WO /tmp/image
+1.2.3.4 RO /dev/acd0
+1.2.3.0/24 RW /tmp/test.img
+2001:DB8:17C0::/64 RW /tmp/foo
+hostname WO /tmp/image
.Ed
.Sh EXIT STATUS
Exit status is 0 on success, or 1 if the command fails.
diff -ruN ggate.orig/ggated/ggated.c ggate/ggated/ggated.c
--- ggate.orig/ggated/ggated.c Thu Nov 10 18:53:21 2005
+++ ggate/ggated/ggated.c Thu Nov 10 18:53:25 2005
@@ -44,6 +44,7 @@
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
+#include <netdb.h>
#include <signal.h>
#include <assert.h>
#include <err.h>
@@ -68,7 +69,7 @@
time_t c_birthtime;
char *c_path;
uint64_t c_token;
- in_addr_t c_srcip;
+ struct sockaddr_storage c_srcaddr;
LIST_ENTRY(ggd_connection) c_next;
};
@@ -83,16 +84,22 @@
#define r_error r_hdr.gh_error
struct ggd_export {
- char *e_path; /* path to device/file */
- in_addr_t e_ip; /* remote IP address */
- in_addr_t e_mask; /* IP mask */
- unsigned e_flags; /* flags (RO/RW) */
- SLIST_ENTRY(ggd_export) e_next;
+ char *e_path; /* path to device/file */
+ struct sockaddr_storage e_addr; /* remote IP address */
+ struct sockaddr_storage e_mask; /* IP mask */
+ unsigned e_flags; /* flags (RO/RW) */
+ SLIST_ENTRY(ggd_export) e_next;
+};
+
+struct ggd_listen {
+ const char *l_name; /* host name / address */
+ struct sockaddr_storage l_addr; /* bind address & port */
+ int l_fd; /* socket */
+ SLIST_ENTRY(ggd_listen) l_next;
};
static const char *exports_file = GGATED_EXPORT_FILE;
static int got_sighup = 0;
-in_addr_t bindaddr;
static TAILQ_HEAD(, ggd_request) inqueue = TAILQ_HEAD_INITIALIZER(inqueue);
static TAILQ_HEAD(, ggd_request) outqueue = TAILQ_HEAD_INITIALIZER(outqueue);
@@ -115,71 +122,88 @@
exit(EXIT_FAILURE);
}
-static char *
-ip2str(in_addr_t ip)
+static const char *
+ip2str(struct sockaddr *addr)
{
- static char sip[16];
+ static char sip[64];
+
+ if (getnameinfo(addr, addr->sa_len, sip, sizeof(sip),
+ NULL, 0, NI_NUMERICHOST) == 0)
+ return (sip);
- snprintf(sip, sizeof(sip), "%u.%u.%u.%u",
- ((ip >> 24) & 0xff),
- ((ip >> 16) & 0xff),
- ((ip >> 8) & 0xff),
- (ip & 0xff));
- return (sip);
+ return ("Unknown");
}
-static in_addr_t
-countmask(unsigned m)
+static struct sockaddr_storage
+countmask(struct sockaddr* addr, int mask) /* also normalizes addr */
{
- in_addr_t mask;
+ struct sockaddr_storage ss;
+ int i, alen;
+ unsigned char *mp, *ap;
- if (m == 0) {
- mask = 0x0;
- } else {
- mask = 1 << (32 - m);
- mask--;
- mask = ~mask;
+ bzero(&ss, sizeof(ss));
+ ss.ss_family = addr->sa_family;
+ ss.ss_len = addr->sa_len;
+
+ switch (addr->sa_family) {
+ case AF_INET:
+ alen = 4; /* 32 bits */
+ ap = (unsigned char*)&((struct sockaddr_in*)addr)->sin_addr.s_addr;
+ mp = (unsigned char*)&((struct sockaddr_in*)&ss)->sin_addr.s_addr;
+ break;
+ case AF_INET6:
+ alen = 16; /* 128 bits */
+ ap = (unsigned char*)&((struct sockaddr_in6*)addr)->sin6_addr.s6_addr;
+ mp = (unsigned char*)&((struct sockaddr_in6*)&ss)->sin6_addr.s6_addr;
+ break;
+ default:
+ g_gate_xlog("Unknown address family in countmask");
+ }
+
+ i = 0;
+ while (mask > 0 && i < alen) {
+ if (mask < 8) {
+ mp[i] = ~(0xff >> mask);
+ ap[i] &= mp[i];
+ } else
+ mp[i] = 0xff;
+ i++;
+ mask -= 8;
}
- return (mask);
+ while (i < alen) { /* zero out remaining bits of addr */
+ ap[i] = 0;
+ i++;
+ }
+
+ return (ss);
}
static void
line_parse(char *line, unsigned lineno)
{
struct ggd_export *ex;
- char *word, *path, *sflags;
- unsigned flags, i, vmask;
- in_addr_t ip, mask;
+ char *pmask, *word, *path, *sflags;
+ unsigned flags, i;
+ int vmask;
+ struct addrinfo hints, *res, *p;
- ip = mask = flags = vmask = 0;
+ flags = vmask = 0;
path = NULL;
sflags = NULL;
+ pmask = NULL;
for (i = 0, word = strtok(line, " \t"); word != NULL;
i++, word = strtok(NULL, " \t")) {
switch (i) {
case 0: /* IP address or host name */
- ip = g_gate_str2ip(strsep(&word, "/"));
- if (ip == INADDR_NONE) {
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(strsep(&word, "/"), NULL, &hints,
+ &res) != 0)
g_gate_xlog("Invalid IP/host name at line %u.",
lineno);
- }
- ip = ntohl(ip);
- if (word == NULL)
- vmask = 32;
- else {
- errno = 0;
- vmask = strtoul(word, NULL, 10);
- if (vmask == 0 && errno != 0) {
- g_gate_xlog("Invalid IP mask value at "
- "line %u.", lineno);
- }
- if ((unsigned)vmask > 32) {
- g_gate_xlog("Invalid IP mask value at line %u.",
- lineno);
- }
- }
- mask = countmask(vmask);
+ pmask = word;
break;
case 1: /* flags */
if (strcasecmp("rd", word) == 0 ||
@@ -209,22 +233,46 @@
if (i != 3)
g_gate_xlog("Too few arguments at line %u.", lineno);
- ex = malloc(sizeof(*ex));
- if (ex == NULL)
- g_gate_xlog("No enough memory.");
- ex->e_path = strdup(path);
- if (ex->e_path == NULL)
- g_gate_xlog("No enough memory.");
-
- /* Made 'and' here. */
- ex->e_ip = (ip & mask);
- ex->e_mask = mask;
- ex->e_flags = flags;
+ p = res;
+ while (p) {
+ ex = malloc(sizeof(*ex));
+ if (ex == NULL)
+ g_gate_xlog("Not enough memory.");
+ ex->e_path = strdup(path);
+ if (ex->e_path == NULL)
+ g_gate_xlog("Not enough memory.");
+
+ if (pmask == NULL && p->ai_family == AF_INET6)
+ vmask = 128;
+ else if (pmask == NULL)
+ vmask = 32;
+ else {
+ errno = 0;
+ vmask = strtoul(pmask, NULL, 10);
+ if (vmask == 0 && errno != 0) {
+ g_gate_xlog("Invalid IP mask value at "
+ "line %u.", lineno);
+ }
+ }
+
+ if ((vmask > 32 && p->ai_family == AF_INET) ||
+ (vmask > 128 && p->ai_family == AF_INET6))
+ g_gate_xlog("Invalid IP mask value at line %u",
+ lineno);
+
+ memcpy(&ex->e_addr, p->ai_addr, p->ai_addrlen);
+ ex->e_mask = countmask((struct sockaddr*)&ex->e_addr, vmask);
+ ex->e_flags = flags;
+
+ SLIST_INSERT_HEAD(&exports, ex, e_next);
- SLIST_INSERT_HEAD(&exports, ex, e_next);
+ g_gate_log(LOG_DEBUG, "Added %s/%u %s %s to exports list.",
+ ip2str((struct sockaddr*)&ex->e_addr), vmask, path, sflags);
- g_gate_log(LOG_DEBUG, "Added %s/%u %s %s to exports list.",
- ip2str(ex->e_ip), vmask, path, sflags);
+ p = p->ai_next;
+ }
+
+ freeaddrinfo(res);
}
static void
@@ -302,12 +350,12 @@
exports_check(struct ggd_export *ex, struct g_gate_cinit *cinit,
struct ggd_connection *conn)
{
- char ipmask[32]; /* 32 == strlen("xxx.xxx.xxx.xxx/xxx.xxx.xxx.xxx")+1 */
+ char ipmask[80]; /* 80 == strlen("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx")+1 */
int error = 0, flags;
- strlcpy(ipmask, ip2str(ex->e_ip), sizeof(ipmask));
+ strlcpy(ipmask, ip2str((struct sockaddr*)&ex->e_addr), sizeof(ipmask));
strlcat(ipmask, "/", sizeof(ipmask));
- strlcat(ipmask, ip2str(ex->e_mask), sizeof(ipmask));
+ strlcat(ipmask, ip2str((struct sockaddr*)&ex->e_mask), sizeof(ipmask));
if ((cinit->gc_flags & GGATE_FLAG_RDONLY) != 0) {
if (ex->e_flags == O_WRONLY) {
g_gate_log(LOG_WARNING, "Read-only access requested, "
@@ -355,17 +403,53 @@
return (0);
}
+static int
+mask_compare(struct sockaddr *a, struct sockaddr *b, struct sockaddr *m) {
+ unsigned char *ap, *bp, *mp;
+ int alen;
+ if (a->sa_family != m->sa_family || b->sa_family != m->sa_family)
+ return (0);
+
+ switch (m->sa_family) {
+ case AF_INET:
+ alen = 4;
+ ap = (unsigned char*)&((struct sockaddr_in*)a)->sin_addr.s_addr;
+ bp = (unsigned char*)&((struct sockaddr_in*)b)->sin_addr.s_addr;
+ mp = (unsigned char*)&((struct sockaddr_in*)m)->sin_addr.s_addr;
+ break;
+ case AF_INET6:
+ alen = 16;
+ ap = (unsigned char*)&((struct sockaddr_in6*)a)->sin6_addr.s6_addr;
+ bp = (unsigned char*)&((struct sockaddr_in6*)b)->sin6_addr.s6_addr;
+ mp = (unsigned char*)&((struct sockaddr_in6*)m)->sin6_addr.s6_addr;
+ break;
+ default:
+ return (0);
+ }
+
+ while (alen > 0) {
+ if ((*ap & *mp) != (*bp & *mp))
+ return (0);
+
+ ap++;
+ bp++;
+ mp++;
+ alen--;
+ }
+
+ return (1);
+}
+
static struct ggd_export *
exports_find(struct sockaddr *s, struct g_gate_cinit *cinit,
struct ggd_connection *conn)
{
struct ggd_export *ex;
- in_addr_t ip;
int error;
- ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr);
SLIST_FOREACH(ex, &exports, e_next) {
- if ((ip & ex->e_mask) != ex->e_ip) {
+ if (!mask_compare(s, (struct sockaddr*)&ex->e_addr,
+ (struct sockaddr*)&ex->e_mask)) {
g_gate_log(LOG_DEBUG, "exports[%s]: IP mismatch.",
ex->e_path);
continue;
@@ -384,7 +468,7 @@
}
}
g_gate_log(LOG_WARNING, "Unauthorized connection from: %s.",
- ip2str(ip));
+ ip2str(s));
errno = EPERM;
return (NULL);
}
@@ -404,7 +488,8 @@
LIST_REMOVE(conn, c_next);
g_gate_log(LOG_NOTICE,
"Connection from %s [%s] removed.",
- ip2str(conn->c_srcip), conn->c_path);
+ ip2str((struct sockaddr*)&conn->c_srcaddr),
+ conn->c_path);
close(conn->c_diskfd);
close(conn->c_sendfd);
close(conn->c_recvfd);
@@ -430,7 +515,6 @@
connection_new(struct g_gate_cinit *cinit, struct sockaddr *s, int sfd)
{
struct ggd_connection *conn;
- in_addr_t ip;
/*
* First, look for old connections.
@@ -449,8 +533,7 @@
return (NULL);
}
conn->c_token = cinit->gc_token;
- ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr);
- conn->c_srcip = ip;
+ memcpy(&conn->c_srcaddr, s, s->sa_len);
conn->c_sendfd = conn->c_recvfd = -1;
if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0)
conn->c_sendfd = sfd;
@@ -461,7 +544,7 @@
time(&conn->c_birthtime);
conn->c_flags = cinit->gc_flags;
LIST_INSERT_HEAD(&connections, conn, c_next);
- g_gate_log(LOG_DEBUG, "Connection created [%s, %s].", ip2str(ip),
+ g_gate_log(LOG_DEBUG, "Connection created [%s, %s].", ip2str(s),
conn->c_path);
return (conn);
}
@@ -470,13 +553,10 @@
connection_add(struct ggd_connection *conn, struct g_gate_cinit *cinit,
struct sockaddr *s, int sfd)
{
- in_addr_t ip;
-
- ip = htonl(((struct sockaddr_in *)(void *)s)->sin_addr.s_addr);
if ((cinit->gc_flags & GGATE_FLAG_SEND) != 0) {
if (conn->c_sendfd != -1) {
g_gate_log(LOG_WARNING,
- "Send socket already exists [%s, %s].", ip2str(ip),
+ "Send socket already exists [%s, %s].", ip2str(s),
conn->c_path);
return (EEXIST);
}
@@ -485,12 +565,12 @@
if (conn->c_recvfd != -1) {
g_gate_log(LOG_WARNING,
"Receive socket already exists [%s, %s].",
- ip2str(ip), conn->c_path);
+ ip2str(s), conn->c_path);
return (EEXIST);
}
conn->c_recvfd = sfd;
}
- g_gate_log(LOG_DEBUG, "Connection added [%s, %s].", ip2str(ip),
+ g_gate_log(LOG_DEBUG, "Connection added [%s, %s].", ip2str(s),
conn->c_path);
return (0);
}
@@ -505,7 +585,7 @@
LIST_REMOVE(conn, c_next);
g_gate_log(LOG_DEBUG, "Connection removed [%s %s].",
- ip2str(conn->c_srcip), conn->c_path);
+ ip2str((struct sockaddr*)&conn->c_srcaddr), conn->c_path);
if (conn->c_sendfd != -1)
close(conn->c_sendfd);
if (conn->c_recvfd != -1)
@@ -815,10 +895,7 @@
static void
log_connection(struct sockaddr *from)
{
- in_addr_t ip;
-
- ip = htonl(((struct sockaddr_in *)(void *)from)->sin_addr.s_addr);
- g_gate_log(LOG_INFO, "Connection from: %s.", ip2str(ip));
+ g_gate_log(LOG_INFO, "Connection from: %s.", ip2str(from));
}
static int
@@ -940,14 +1017,16 @@
int
main(int argc, char *argv[])
{
- struct sockaddr_in serv;
- struct sockaddr from;
+ SLIST_HEAD(, ggd_listen) listens = SLIST_HEAD_INITIALIZER(&listens);
+ struct ggd_listen *cl, *nl;
+ struct addrinfo hints, *res, *p;
+ struct sockaddr_storage from;
socklen_t fromlen;
- int sfd, tmpsfd;
- unsigned port;
+ int maxfd, tmpsfd;
+ fd_set listenfds;
+ const char *port;
- bindaddr = htonl(INADDR_ANY);
- port = G_GATE_PORT;
+ port = G_GATE_PORT_STR;
for (;;) {
int ch;
@@ -956,20 +1035,17 @@
break;
switch (ch) {
case 'a':
- bindaddr = g_gate_str2ip(optarg);
- if (bindaddr == INADDR_NONE) {
- errx(EXIT_FAILURE,
- "Invalid IP/host name to bind to.");
- }
+ nl = malloc(sizeof(*nl));
+ bzero(nl, sizeof(*nl));
+ nl->l_name = optarg;
+ /* delay resolution until we know port number */
+ SLIST_INSERT_HEAD(&listens, nl, l_next);
break;
case 'n':
nagle = 0;
break;
case 'p':
- errno = 0;
- port = strtoul(optarg, NULL, 10);
- if (port == 0 && errno != 0)
- errx(EXIT_FAILURE, "Invalid port.");
+ port = optarg;
break;
case 'R':
errno = 0;
@@ -998,6 +1074,79 @@
exports_file = argv[0];
exports_get();
+ if (SLIST_EMPTY(&listens)) {
+ /* Bind to all address families */
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_flags = AI_PASSIVE;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(NULL, port, &hints, &res))
+ g_gate_xlog("Cannot get passive address: %s",
+ strerror(errno));
+
+ p = res;
+ while (p) {
+ nl = malloc(sizeof(*nl));
+ bzero(nl, sizeof(*nl));
+ memcpy(&nl->l_addr, p->ai_addr, p->ai_addrlen);
+ SLIST_INSERT_HEAD(&listens, nl, l_next);
+
+ p = p->ai_next;
+ }
+ freeaddrinfo(res);
+ } else {
+ /* Bind to some specific addresses */
+ SLIST_FOREACH(cl, &listens, l_next) {
+ bzero(&hints, sizeof(hints));
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ if (getaddrinfo(cl->l_name, port, &hints, &res))
+ g_gate_xlog("Invalid IP/host name to bind to: "
+ "%s", cl->l_name);
+
+ /* Re-use current list entry for first match, add
+ * new ones after that */
+ p = res;
+ nl = cl;
+ while (p) {
+ if (p != res) {
+ nl = malloc(sizeof(*nl));
+ bzero(nl, sizeof(*nl));
+ }
+
+ memcpy(&nl->l_addr, p->ai_addr, p->ai_addrlen);
+
+ if (p != res) {
+ SLIST_INSERT_HEAD(&listens, nl, l_next);
+ }
+ p = p->ai_next;
+ }
+ freeaddrinfo(res);
+ }
+ }
+
+ /* Actually create sockets and bind to them */
+ maxfd = 0;
+ SLIST_FOREACH(cl, &listens, l_next) {
+ cl->l_fd = socket(cl->l_addr.ss_family, SOCK_STREAM, 0);
+ if (cl->l_fd == -1)
+ g_gate_xlog("Cannot open stream socket: %s.",
+ strerror(errno));
+ g_gate_socket_settings(cl->l_fd);
+
+ if (bind(cl->l_fd, (struct sockaddr *)&cl->l_addr,
+ cl->l_addr.ss_len) == -1)
+ g_gate_xlog("bind(): %s.", strerror(errno));
+ if (listen(cl->l_fd, 5) == -1)
+ g_gate_xlog("listen(): %s.", strerror(errno));
+
+ if (maxfd <= cl->l_fd)
+ maxfd = cl->l_fd + 1;
+
+ g_gate_log(LOG_INFO, "Listen on address: %s (%s).",
+ ip2str((struct sockaddr *)&cl->l_addr), port);
+ }
+
if (!g_gate_verbose) {
/* Run in daemon mode. */
if (daemon(0, 0) == -1)
@@ -1005,40 +1154,44 @@
}
signal(SIGCHLD, SIG_IGN);
-
- sfd = socket(AF_INET, SOCK_STREAM, 0);
- if (sfd == -1)
- g_gate_xlog("Cannot open stream socket: %s.", strerror(errno));
- bzero(&serv, sizeof(serv));
- serv.sin_family = AF_INET;
- serv.sin_addr.s_addr = bindaddr;
- serv.sin_port = htons(port);
-
- g_gate_socket_settings(sfd);
-
- if (bind(sfd, (struct sockaddr *)&serv, sizeof(serv)) == -1)
- g_gate_xlog("bind(): %s.", strerror(errno));
- if (listen(sfd, 5) == -1)
- g_gate_xlog("listen(): %s.", strerror(errno));
-
- g_gate_log(LOG_INFO, "Listen on port: %d.", port);
-
signal(SIGHUP, huphandler);
for (;;) {
- fromlen = sizeof(from);
- tmpsfd = accept(sfd, &from, &fromlen);
- if (tmpsfd == -1)
- g_gate_xlog("accept(): %s.", strerror(errno));
+ FD_ZERO(&listenfds);
+ SLIST_FOREACH(cl, &listens, l_next) {
+ FD_SET(cl->l_fd, &listenfds);
+ }
+
+ select(maxfd, &listenfds, NULL, NULL, NULL);
if (got_sighup) {
got_sighup = 0;
exports_get();
}
- if (!handshake(&from, tmpsfd))
- close(tmpsfd);
+ SLIST_FOREACH(cl, &listens, l_next) {
+ if (!FD_ISSET(cl->l_fd, &listenfds))
+ continue;
+
+ fromlen = sizeof(from);
+ tmpsfd = accept(cl->l_fd, (struct sockaddr*)&from,
+ &fromlen);
+
+ if (tmpsfd == -1) {
+ g_gate_log(LOG_WARNING, "accept(): %s.",
+ strerror(errno));
+ continue;
+ }
+
+ if (!handshake((struct sockaddr*)&from, tmpsfd))
+ close(tmpsfd);
+ }
+ }
+ while (!SLIST_EMPTY(&listens)) {
+ cl = SLIST_FIRST(&listens);
+ close(cl->l_fd);
+ SLIST_REMOVE_HEAD(&listens, l_next);
+ free(cl);
}
- close(sfd);
exit(EXIT_SUCCESS);
}
diff -ruN ggate.orig/shared/ggate.c ggate/shared/ggate.c
--- ggate.orig/shared/ggate.c Thu Nov 10 18:53:21 2005
+++ ggate/shared/ggate.c Thu Nov 10 18:53:25 2005
@@ -375,21 +375,3 @@
exit(EXIT_SUCCESS);
}
#endif /* LIBGEOM */
-
-in_addr_t
-g_gate_str2ip(const char *str)
-{
- struct hostent *hp;
- in_addr_t ip;
-
- ip = inet_addr(str);
- if (ip != INADDR_NONE) {
- /* It is a valid IP address. */
- return (ip);
- }
- /* Check if it is a valid host name. */
- hp = gethostbyname(str);
- if (hp == NULL)
- return (INADDR_NONE);
- return (((struct in_addr *)(void *)hp->h_addr)->s_addr);
-}
diff -ruN ggate.orig/shared/ggate.h ggate/shared/ggate.h
--- ggate.orig/shared/ggate.h Thu Nov 10 18:53:21 2005
+++ ggate/shared/ggate.h Thu Nov 10 18:53:25 2005
@@ -33,6 +33,7 @@
#include <stdarg.h>
#define G_GATE_PORT 3080
+#define G_GATE_PORT_STR "3080"
#define G_GATE_RCVBUF 131072
#define G_GATE_SNDBUF 131072
@@ -110,7 +111,6 @@
#ifdef LIBGEOM
void g_gate_list(int unit, int verbose);
#endif
-in_addr_t g_gate_str2ip(const char *str);
/*
* g_gate_swap2h_* - functions swap bytes to host byte order (from big endian).
--- ggate_ipv6_2.patch ends here ---
>Release-Note:
>Audit-Trail:
>Unformatted:
help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20051111010811.1E7032D2D3>
