[PATCH 11/31] ipv6: introduce union iaddr
Ian Jackson
ijackson at chiark.greenend.org.uk
Sat Sep 20 01:32:06 BST 2014
Replace many occurrences of sockaddr_in by a new union, iaddr.
Everywhere that fills in an address has been modified to look into the
subfields of iaddr. But there is not yet any support for a union
iaddr to contain anything other than a sockaddr_in. This will be
added gradually in forthcoming patches, starting at consumers and
working back.
Additionally, a couple of places that specified a port and address as
a uint16_t and uint32_t have been converted.
We have changed only transport addresses - that is, addresses on the
public network. VPN addresses remain IPv4 only.
We provide a few helper functions for manipulating union iaddr, such
as iaddr_to_string (which replaces saddr_to_string).
Signed-off-by: Ian Jackson <ijackson at chiark.greenend.org.uk>
---
resolver.c | 14 +++++------
secnet.h | 7 +++++-
udp.c | 78 ++++++++++++++++++++++++++++--------------------------------
util.c | 36 ++++++++++++++++++++++++++++
util.h | 4 ++++
5 files changed, 90 insertions(+), 49 deletions(-)
diff --git a/resolver.c b/resolver.c
index 5360966..f7cd373 100644
--- a/resolver.c
+++ b/resolver.c
@@ -44,9 +44,9 @@ static bool_t resolve_request(void *sst, cstring_t name,
struct comm_addr ca;
FILLZERO(ca);
ca.comm=comm;
- ca.sin.sin_family=AF_INET;
- ca.sin.sin_port=htons(port);
- if (inet_aton(trimmed,&ca.sin.sin_addr))
+ ca.ia.sin.sin_family=AF_INET;
+ ca.ia.sin.sin_port=htons(port);
+ if (inet_aton(trimmed,&ca.ia.sin.sin_addr))
cb(cst,&ca,1);
else
cb(cst,0,0);
@@ -112,10 +112,10 @@ static void resolver_afterpoll(void *sst, struct pollfd *fds, int nfds)
/* copy fields individually so we leave holes zeroed: */
switch (ra->addr.sa.sa_family) {
case AF_INET:
- assert(ra->len == sizeof(ca->sin));
- ca->sin.sin_family=ra->addr.inet.sin_family;
- ca->sin.sin_addr= ra->addr.inet.sin_addr;
- ca->sin.sin_port= htons(q->port);
+ assert(ra->len == sizeof(ca->ia.sin));
+ ca->ia.sin.sin_family=ra->addr.inet.sin_family;
+ ca->ia.sin.sin_addr= ra->addr.inet.sin_addr;
+ ca->ia.sin.sin_port= htons(q->port);
wslot++;
break;
default:
diff --git a/secnet.h b/secnet.h
index 900e699..26c3e4f 100644
--- a/secnet.h
+++ b/secnet.h
@@ -28,6 +28,11 @@ typedef const char *cstring_t;
#define True (_Bool)1
typedef _Bool bool_t;
+union iaddr {
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+};
+
#define ASSERT(x) do { if (!(x)) { fatal("assertion failed line %d file " \
__FILE__,__LINE__); } } while(0)
@@ -328,7 +333,7 @@ struct comm_addr {
must start by memsetting it with FILLZERO, or some
equivalent. */
struct comm_if *comm;
- struct sockaddr_in sin;
+ union iaddr ia;
};
/* Return True if the packet was processed, and shouldn't be passed to
diff --git a/udp.c b/udp.c
index 552a58e..f82acca 100644
--- a/udp.c
+++ b/udp.c
@@ -40,37 +40,21 @@ struct udp {
closure_t cl;
struct comm_if ops;
struct cloc loc;
- uint32_t addr;
- uint16_t port;
+ union iaddr addr;
int fd;
string_t authbind;
struct buffer_if *rbuf;
struct notify_list *notify;
bool_t use_proxy;
- struct sockaddr_in proxy;
+ union iaddr proxy;
};
-static const char *saddr_to_string(const struct sockaddr_in *sin) {
- static char bufs[2][100];
- static int b;
-
- b ^= 1;
- snprintf(bufs[b], sizeof(bufs[b]), "[%s]:%d",
- inet_ntoa(sin->sin_addr),
- ntohs(sin->sin_port));
- return bufs[b];
-}
-
static const char *addr_to_string(void *commst, const struct comm_addr *ca) {
struct udp *st=commst;
static char sbuf[100];
- struct sockaddr_in la;
- la.sin_addr.s_addr=htonl(st->addr);
- la.sin_port=htons(st->port);
-
snprintf(sbuf, sizeof(sbuf), "udp:%s-%s",
- saddr_to_string(&la), saddr_to_string(&ca->sin));
+ iaddr_to_string(&st->addr), iaddr_to_string(&ca->ia));
return sbuf;
}
@@ -91,7 +75,7 @@ static int udp_beforepoll(void *state, struct pollfd *fds, int *nfds_io,
static void udp_afterpoll(void *state, struct pollfd *fds, int nfds)
{
struct udp *st=state;
- struct sockaddr_in from;
+ union iaddr from;
socklen_t fromlen;
struct notify_list *n;
bool_t done;
@@ -113,21 +97,22 @@ static void udp_afterpoll(void *state, struct pollfd *fds, int nfds)
/* Check that the packet came from our poxy server;
we shouldn't be contacted directly by anybody else
(since they can trivially forge source addresses) */
- if (memcmp(&from.sin_addr,&st->proxy.sin_addr,4)!=0 ||
- memcmp(&from.sin_port,&st->proxy.sin_port,2)!=0) {
+ if (!iaddr_equal(&from,&st->proxy)) {
Message(M_INFO,"udp: received packet that's not "
"from the proxy\n");
BUF_FREE(st->rbuf);
continue;
}
- memcpy(&from.sin_addr,buf_unprepend(st->rbuf,4),4);
+ /* proxy protocol supports ipv4 transport only */
+ from.sa.sa_family=AF_INET;
+ memcpy(&from.sin.sin_addr,buf_unprepend(st->rbuf,4),4);
buf_unprepend(st->rbuf,2);
- memcpy(&from.sin_port,buf_unprepend(st->rbuf,2),2);
+ memcpy(&from.sin.sin_port,buf_unprepend(st->rbuf,2),2);
}
struct comm_addr ca;
FILLZERO(ca);
ca.comm=&st->ops;
- ca.sin=from;
+ ca.ia=from;
done=False;
for (n=st->notify; n; n=n->next) {
if (n->fn(n->state, st->rbuf, &ca)) {
@@ -197,15 +182,21 @@ static bool_t udp_sendmsg(void *commst, struct buffer_if *buf,
if (st->use_proxy) {
sa=buf_prepend(buf,8);
- memcpy(sa,&dest->sin.sin_addr,4);
+ if (dest->ia.sa.sa_family != AF_INET) {
+ Message(M_INFO,
+ "udp: proxy means dropping outgoing non-IPv4 packet to %s\n",
+ iaddr_to_string(&dest->ia));
+ return False;
+ }
+ memcpy(sa,&dest->ia.sin.sin_addr,4);
memset(sa+4,0,4);
- memcpy(sa+6,&dest->sin.sin_port,2);
+ memcpy(sa+6,&dest->ia.sin.sin_port,2);
sendto(st->fd,sa,buf->size+8,0,(struct sockaddr *)&st->proxy,
sizeof(st->proxy));
buf_unprepend(buf,8);
} else {
sendto(st->fd, buf->start, buf->size, 0,
- (struct sockaddr *)&dest->sin, sizeof(dest->sin));
+ &dest->ia.sa, iaddr_socklen(&dest->ia));
}
return True;
@@ -214,7 +205,7 @@ static bool_t udp_sendmsg(void *commst, struct buffer_if *buf,
static void udp_phase_hook(void *sst, uint32_t new_phase)
{
struct udp *st=sst;
- struct sockaddr_in addr;
+ union iaddr addr;
st->fd=socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
if (st->fd<0) {
@@ -229,10 +220,7 @@ static void udp_phase_hook(void *sst, uint32_t new_phase)
st->loc.file,st->loc.line);
}
- FILLZERO(addr);
- addr.sin_family=AF_INET;
- addr.sin_addr.s_addr=htonl(st->addr);
- addr.sin_port=htons(st->port);
+ addr=st->addr;
if (st->authbind) {
pid_t c;
int status;
@@ -245,8 +233,15 @@ static void udp_phase_hook(void *sst, uint32_t new_phase)
}
if (c==0) {
char *argv[4], addrstr[9], portstr[5];
- sprintf(addrstr,"%08lX",(long)addr.sin_addr.s_addr);
- sprintf(portstr,"%04X",addr.sin_port);
+ switch (addr.sa.sa_family) {
+ case AF_INET:
+ sprintf(addrstr,"%08lX",(long)addr.sin.sin_addr.s_addr);
+ sprintf(portstr,"%04X",addr.sin.sin_port);
+ break;
+ default:
+ fatal("udp (%s:%d): unsupported address family for authbind",
+ st->loc.file,st->loc.line);
+ }
argv[0]=st->authbind;
argv[1]=addrstr;
argv[2]=portstr;
@@ -296,7 +291,7 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
st->ops.release_notify=release_notify;
st->ops.sendmsg=udp_sendmsg;
st->ops.addr_to_string=addr_to_string;
- st->port=0;
+ FILLZERO(st->addr);
st->use_proxy=False;
i=list_elem(args,0);
@@ -305,27 +300,28 @@ static list_t *udp_apply(closure_t *self, struct cloc loc, dict_t *context,
}
d=i->data.dict;
+ st->addr.sa.sa_family=AF_INET;
j=dict_find_item(d,"address",False,"udp",st->loc);
- st->addr=j?string_item_to_ipaddr(j, "udp"):INADDR_ANY;
- st->port=dict_read_number(d,"port",True,"udp",st->loc,0);
+ st->addr.sin.sin_addr.s_addr=j?string_item_to_ipaddr(j, "udp"):INADDR_ANY;
+ st->addr.sin.sin_port=dict_read_number(d,"port",True,"udp",st->loc,0);
st->rbuf=find_cl_if(d,"buffer",CL_BUFFER,True,"udp",st->loc);
st->authbind=dict_read_string(d,"authbind",False,"udp",st->loc);
l=dict_lookup(d,"proxy");
if (l) {
st->use_proxy=True;
FILLZERO(st->proxy);
- st->proxy.sin_family=AF_INET;
+ st->proxy.sa.sa_family=AF_INET;
i=list_elem(l,0);
if (!i || i->type!=t_string) {
cfgfatal(st->loc,"udp","proxy must supply ""addr"",port\n");
}
a=string_item_to_ipaddr(i,"proxy");
- st->proxy.sin_addr.s_addr=htonl(a);
+ st->proxy.sin.sin_addr.s_addr=htonl(a);
i=list_elem(l,1);
if (!i || i->type!=t_number) {
cfgfatal(st->loc,"udp","proxy must supply ""addr"",port\n");
}
- st->proxy.sin_port=htons(i->data.number);
+ st->proxy.sin.sin_port=htons(i->data.number);
}
update_max_start_pad(&comm_max_start_pad, st->use_proxy ? 8 : 0);
diff --git a/util.c b/util.c
index 094870f..3e0f5ce 100644
--- a/util.c
+++ b/util.c
@@ -462,3 +462,39 @@ extern void slilog_part(struct log_if *lf, int priority, const char *message, ..
vslilog_part(lf,priority,message,ap);
va_end(ap);
}
+
+const char *iaddr_to_string(const union iaddr *ia)
+{
+ static char bufs[2][100];
+ static int b;
+
+ b ^= 1;
+
+ assert(ia->sa.sa_family == AF_INET);
+
+ snprintf(bufs[b], sizeof(bufs[b]), "[%s]:%d",
+ inet_ntoa(ia->sin.sin_addr),
+ ntohs(ia->sin.sin_port));
+ return bufs[b];
+}
+
+bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib)
+{
+ if (ia->sa.sa_family != ib->sa.sa_family)
+ return 0;
+ switch (ia->sa.sa_family) {
+ case AF_INET:
+ return ia->sin.sin_addr.s_addr == ib->sin.sin_addr.s_addr
+ && ia->sin.sin_port == ib->sin.sin_port;
+ default:
+ abort();
+ }
+}
+
+int iaddr_socklen(const union iaddr *ia)
+{
+ switch (ia->sa.sa_family) {
+ case AF_INET: return sizeof(ia->sin);
+ default: abort();
+ }
+}
diff --git a/util.h b/util.h
index 29b68e7..43a98db 100644
--- a/util.h
+++ b/util.h
@@ -56,6 +56,10 @@ extern void send_nak(const struct comm_addr *dest, uint32_t our_index,
extern int consttime_memeq(const void *s1, const void *s2, size_t n);
+const char *iaddr_to_string(const union iaddr *ia);
+bool_t iaddr_equal(const union iaddr *ia, const union iaddr *ib);
+int iaddr_socklen(const union iaddr *ia);
+
#define MINMAX(ae,be,op) ({ \
typeof((ae)) a=(ae); \
typeof((be)) b=(be); \
--
1.7.10.4
More information about the sgo-software-discuss
mailing list