Just like that. Of course, the hard work was done earlier.
Matches the address of one of the machine's network interfaces.
.TP
.I address
Matches the address of one of the machine's network interfaces.
.TP
.I address
-Matches just the given address. An
+Matches just the given IPv4 or IPv6 address. An
-may be enclosed in square brackets.
+may be enclosed in square brackets; IPv6 addresses must be so enclosed,
+because colons are significant in the rest of the ACL syntax.
.TP
.IB address \- address
Matches any address which falls in the given range. Addresses are
.TP
.IB address \- address
Matches any address which falls in the given range. Addresses are
enum { WANT_FRESH, WANT_EXISTING }; /* Socket address dispositions */
enum { DENY, ALLOW }; /* ACL verdicts */
enum { WANT_FRESH, WANT_EXISTING }; /* Socket address dispositions */
enum { DENY, ALLOW }; /* ACL verdicts */
-static int address_families[] = { AF_INET, -1 };
+static int address_families[] = { AF_INET, AF_INET6, -1 };
#define ADDRBUFSZ 64
/* Address representations. */
typedef union ipaddr {
struct in_addr v4;
#define ADDRBUFSZ 64
/* Address representations. */
typedef union ipaddr {
struct in_addr v4;
} ipaddr;
/* Convenient socket address hacking. */
typedef union address {
struct sockaddr sa;
struct sockaddr_in sin;
} ipaddr;
/* Convenient socket address hacking. */
typedef union address {
struct sockaddr sa;
struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
} address;
/* Access control list nodes */
} address;
/* Access control list nodes */
int af;
ipaddr addr;
} full_ipaddr;
int af;
ipaddr addr;
} full_ipaddr;
-#define MAX_LOCAL_IPADDRS 16
+#define MAX_LOCAL_IPADDRS 64
static full_ipaddr local_ipaddrs[MAX_LOCAL_IPADDRS];
static int n_local_ipaddrs;
static full_ipaddr local_ipaddrs[MAX_LOCAL_IPADDRS];
static int n_local_ipaddrs;
/* Socket address casts */
#define SA(sa) ((struct sockaddr *)(sa))
#define SIN(sa) ((struct sockaddr_in *)(sa))
/* Socket address casts */
#define SA(sa) ((struct sockaddr *)(sa))
#define SIN(sa) ((struct sockaddr_in *)(sa))
+#define SIN6(sa) ((struct sockaddr_in6 *)(sa))
#define SUN(sa) ((struct sockaddr_un *)(sa))
/* Raw bytes */
#define SUN(sa) ((struct sockaddr_un *)(sa))
/* Raw bytes */
{
switch (af) {
case AF_INET:
{
switch (af) {
case AF_INET:
return (1);
default:
return (0);
return (1);
default:
return (0);
{
switch (af) {
case AF_INET: return (sizeof(struct sockaddr_in));
{
switch (af) {
case AF_INET: return (sizeof(struct sockaddr_in));
+ case AF_INET6: return (sizeof(struct sockaddr_in6));
{
switch (af) {
case AF_INET: return 32;
{
switch (af) {
case AF_INET: return 32;
+ case AF_INET6: return 128;
if ((aa&m) == 0 && (bb&m) == m) return (32 - simple_mask_length(m));
else return (-1);
} break;
if ((aa&m) == 0 && (bb&m) == m) return (32 - simple_mask_length(m));
else return (-1);
} break;
+ case AF_INET6: {
+ const uint8_t *aa = a->v6.s6_addr, *bb = b->v6.s6_addr;
+ unsigned m;
+ unsigned n;
+ int i;
+
+ for (i = 0; i < 16 && aa[i] == bb[i]; i++);
+ n = 8*i;
+ if (i < 16) {
+ m = aa[i]^bb[i];
+ if ((aa[i]&m) != 0 || (bb[i]&m) != m) return (-1);
+ n += 8 - simple_mask_length(m);
+ for (i++; i < 16; i++)
+ if (aa[i] || bb[i] != 0xff) return (-1);
+ }
+ return (n);
+ } break;
{
switch (sa->sa_family) {
case AF_INET: return (ntohs(SIN(sa)->sin_port));
{
switch (sa->sa_family) {
case AF_INET: return (ntohs(SIN(sa)->sin_port));
+ case AF_INET6: return (ntohs(SIN6(sa)->sin6_port));
{
switch (sa->sa_family) {
case AF_INET: SIN(sa)->sin_port = htons(port); break;
{
switch (sa->sa_family) {
case AF_INET: SIN(sa)->sin_port = htons(port); break;
+ case AF_INET6: SIN6(sa)->sin6_port = htons(port); break;
{
switch (sa->sa_family) {
case AF_INET: a->v4 = SIN(sa)->sin_addr; break;
{
switch (sa->sa_family) {
case AF_INET: a->v4 = SIN(sa)->sin_addr; break;
+ case AF_INET6: a->v6 = SIN6(sa)->sin6_addr; break;
{
switch (af) {
case AF_INET: return (a->v4.s_addr == b->v4.s_addr);
{
switch (af) {
case AF_INET: return (a->v4.s_addr == b->v4.s_addr);
+ case AF_INET6: return (memcmp(a->v6.s6_addr, b->v6.s6_addr, 16) == 0);
return (ntohl(a->v4.s_addr) <= addr &&
addr <= ntohl(b->v4.s_addr));
} break;
return (ntohl(a->v4.s_addr) <= addr &&
addr <= ntohl(b->v4.s_addr));
} break;
+ case AF_INET6: {
+ const uint8_t *ss = SIN6(sa)->sin6_addr.s6_addr;
+ const uint8_t *aa = a->v6.s6_addr, *bb = b->v6.s6_addr;
+ int h = 1, l = 1;
+ int i;
+
+ for (i = 0; h && l && i < 16; i++, ss++, aa++, bb++) {
+ if (*ss < *aa || *bb < *ss) return (0);
+ if (*aa < *ss) l = 0;
+ if (*ss < *bb) h = 0;
+ }
+ return (1);
+ } break;
sin->sin_port = 0;
sin->sin_addr.s_addr = INADDR_ANY;
} break;
sin->sin_port = 0;
sin->sin_addr.s_addr = INADDR_ANY;
} break;
+ case AF_INET6: {
+ struct sockaddr_in6 *sin6 = SIN6(sa);
+ memset(sin6, 0, sizeof(sin6));
+ sin6->sin6_family = AF_INET6;
+ sin6->sin6_port = 0;
+ sin6->sin6_addr = in6addr_any;
+ sin6->sin6_scope_id = 0;
+ sin6->sin6_flowinfo = 0;
+ } break;
if (highp) addr |= ~mask;
a->v4.s_addr = htonl(addr & 0xffffffff);
} break;
if (highp) addr |= ~mask;
a->v4.s_addr = htonl(addr & 0xffffffff);
} break;
+ case AF_INET6: {
+ int i = plen/8;
+ unsigned m = (0xff << (8 - plen%8)) & 0xff;
+ unsigned s = highp ? 0xff : 0;
+ if (m) {
+ a->v6.s6_addr[i] = (a->v6.s6_addr[i] & m) | (s & ~m);
+ i++;
+ }
+ for (; i < 16; i++) a->v6.s6_addr[i] = s;
+ } break;
}
WANT(1); PUTC(0);
} break;
}
WANT(1); PUTC(0);
} break;
+ case AF_INET: case AF_INET6: {
char addrbuf[NI_MAXHOST], portbuf[NI_MAXSERV];
int err = getnameinfo(sa, len,
addrbuf, sizeof(addrbuf),
char addrbuf[NI_MAXHOST], portbuf[NI_MAXSERV];
int err = getnameinfo(sa, len,
addrbuf, sizeof(addrbuf),
/* Guess the family of a textual socket address. */
static int guess_address_family(const char *p)
/* Guess the family of a textual socket address. */
static int guess_address_family(const char *p)
+ { return (strchr(p, ':') ? AF_INET6 : AF_INET); }
/* Parse a socket address P and write the result to SA. */
static int parse_sockaddr(struct sockaddr *sa, const char *p)
/* Parse a socket address P and write the result to SA. */
static int parse_sockaddr(struct sockaddr *sa, const char *p)