This depends on ADNS for IPv6 name resolution.
def _setaddr(me, addr):
"""Set the peer's address."""
def _setaddr(me, addr):
"""Set the peer's address."""
+ if addr[0] in ['INET', 'INET6']:
af, ipaddr, port = addr
try:
name, _ = S.getnameinfo((ipaddr, int(port)),
S.NI_NUMERICSERV | S.NI_NAMEREQD)
except S.gaierror:
af, ipaddr, port = addr
try:
name, _ = S.getnameinfo((ipaddr, int(port)),
S.NI_NUMERICSERV | S.NI_NAMEREQD)
except S.gaierror:
- me.addr = '%s %s:%s' % (af, ipaddr, port)
+ me.addr = '%s %s%s%s:%s' % (af,
+ af == 'INET6' and '[' or '',
+ ipaddr,
+ af == 'INET6' and ']' or '',
+ port)
else:
me.addr = '%s %s:%s [%s]' % (af, name, port, ipaddr)
else:
else:
me.addr = '%s %s:%s [%s]' % (af, name, port, ipaddr)
else:
* e_name, e_addr, e_port, c_keepalive, l_tunnel: widgets in the dialog
"""
* e_name, e_addr, e_port, c_keepalive, l_tunnel: widgets in the dialog
"""
+ AFS = ['ANY', 'INET', 'INET6']
+
def __init__(me):
"""Initialize the dialogue."""
MyDialog.__init__(me, 'Add peer',
def __init__(me):
"""Initialize the dialogue."""
MyDialog.__init__(me, 'Add peer',
me.e_name = table.labelled('Name',
ValidatingEntry(r'^[^\s.:]+$', '', 16),
width = 3)
me.e_name = table.labelled('Name',
ValidatingEntry(r'^[^\s.:]+$', '', 16),
width = 3)
+ me.l_af = table.labelled('Family', combo_box_text(),
+ newlinep = True, width = 3)
+ for af in me.AFS:
+ me.l_af.append_text(af)
+ me.l_af.set_active(0)
me.e_addr = table.labelled('Address',
me.e_addr = table.labelled('Address',
- ValidatingEntry(r'^[a-zA-Z0-9.-]+$', '', 24),
+ ValidatingEntry(r'^[a-zA-Z0-9.-:]+$', '', 24),
newlinep = True)
me.e_port = table.labelled('Port',
ValidatingEntry(numericvalidate(0, 65535),
newlinep = True)
me.e_port = table.labelled('Port',
ValidatingEntry(numericvalidate(0, 65535),
"""Handle an OK press: create the peer."""
try:
t = me.l_tunnel.get_active()
"""Handle an OK press: create the peer."""
try:
t = me.l_tunnel.get_active()
+ afix = me.l_af.get_active()
me._addpeer(me.e_name.get_text(),
me._addpeer(me.e_name.get_text(),
me.e_addr.get_text(),
me.e_port.get_text(),
keepalive = (me.c_keepalive.get_active() and
me.e_addr.get_text(),
me.e_port.get_text(),
keepalive = (me.c_keepalive.get_active() and
static uint32 hash(const addr *a)
{
static uint32 hash(const addr *a)
{
+ size_t i;
+ uint32 h;
+
switch (a->sa.sa_family) {
case AF_INET:
return (U32(0x4eaac1b7ul*AF_INET +
0xa5dbc837ul*a->sin.sin_addr.s_addr +
0x3b049e83ul*a->sin.sin_port));
switch (a->sa.sa_family) {
case AF_INET:
return (U32(0x4eaac1b7ul*AF_INET +
0xa5dbc837ul*a->sin.sin_addr.s_addr +
0x3b049e83ul*a->sin.sin_port));
+ case AF_INET6:
+ for (i = 0, h = 0; i < 16; i++)
+ h = 0x6bd26a67ul*h + a->sin6.sin6_addr.s6_addr[i];
+ return (U32(0x4eaac1b7ul*AF_INET6 +
+ 0xa5dbc837ul*h +
+ 0x1d94eab4ul*a->sin6.sin6_scope_id +
+ 0x3b049e83ul*a->sin6.sin6_port));
case AF_INET:
return (a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr &&
a->sin.sin_port == b->sin.sin_port);
case AF_INET:
return (a->sin.sin_addr.s_addr == b->sin.sin_addr.s_addr &&
a->sin.sin_port == b->sin.sin_port);
+ case AF_INET6:
+ return (!memcmp(a->sin6.sin6_addr.s6_addr,
+ b->sin6.sin6_addr.s6_addr, 16) &&
+ a->sin6.sin6_port == b->sin6.sin6_port);
{
int fd;
int len = PKBUFSZ;
{
int fd;
int len = PKBUFSZ;
int i;
struct addrinfo *ai;
unsigned port, lastport = 0;
int i;
struct addrinfo *ai;
unsigned port, lastport = 0;
if ((fd = socket(ai->ai_family, SOCK_DGRAM, 0)) < 0)
die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno));
if ((fd = socket(ai->ai_family, SOCK_DGRAM, 0)) < 0)
die(EXIT_FAILURE, "socket creation failed: %s", strerror(errno));
+ if (i == AFIX_INET6 &&
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &yes, sizeof(yes))) {
+ die(EXIT_FAILURE, "failed to set IPv6-only state: %s",
+ strerror(errno));
+ }
assert(ai->ai_addrlen <= sizeof(a));
memcpy(&a, ai->ai_addr, ai->ai_addrlen);
if ((port = getport(&a)) == 0 && lastport) setport(&a, lastport);
assert(ai->ai_addrlen <= sizeof(a));
memcpy(&a, ai->ai_addr, ai->ai_addrlen);
if ((port = getport(&a)) == 0 && lastport) setport(&a, lastport);
{
switch (a->sa.sa_family) {
case AF_INET: return (sizeof(a->sin));
{
switch (a->sa.sa_family) {
case AF_INET: return (sizeof(a->sin));
+ case AF_INET6: return (sizeof(a->sin6));
{
switch (a->sa.sa_family) {
case AF_INET: return (ntohs(a->sin.sin_port)); break;
{
switch (a->sa.sa_family) {
case AF_INET: return (ntohs(a->sin.sin_port)); break;
+ case AF_INET6: return (ntohs(a->sin6.sin6_port)); break;
{
switch (a->sa.sa_family) {
case AF_INET: a->sin.sin_port = htons(port); break;
{
switch (a->sa.sa_family) {
case AF_INET: a->sin.sin_port = htons(port); break;
+ case AF_INET6: a->sin6.sin6_port = htons(port); break;
is given as a plain decimal number. On input, DNS hostnames and
symbolic port names are permitted; if omitted, the default port 4070 is
used.
is given as a plain decimal number. On input, DNS hostnames and
symbolic port names are permitted; if omitted, the default port 4070 is
used.
+.TP
+.BI "INET6 " address " \fR[" port \fR]
+An Internet socket, naming an IPv6 address and UDP port. On output, the
+.I address
+is always in numeric hex-and-colons form, and the
+.I port
+is given as a plain decimal number. On input, DNS hostnames and
+symbolic port names may be permitted, depending on how
+.B tripe
+was compiled; if omitted, the default port 4070 is used.
.PP
If, on input, no recognized address family token is found, the following
tokens are assumed to represent an
.PP
If, on input, no recognized address family token is found, the following
tokens are assumed to represent an
is the MTU of the path to the peer, then the tunnel MTU should be
.IP
.I MTU
is the MTU of the path to the peer, then the tunnel MTU should be
.IP
.I MTU
+\-
+.I header-length
+\- 9 \-
-allowing 20 bytes of IP header, 8 bytes of UDP header, a packet type
-octet, and the bulk-crypto transform overhead (which includes the
-sequence number).
+allowing
+.I header-length
+= 20 (IPv4) or 40 (IPv6) bytes of IP header, 8 bytes of UDP header, a
+packet type octet, and the bulk-crypto transform overhead (which
+includes the sequence number).
.RE
.SP
.BI "BGCANCEL " tag
.RE
.SP
.BI "BGCANCEL " tag
An error occurred during the attempt to become a daemon, as reported by
.IR message .
.SP
An error occurred during the attempt to become a daemon, as reported by
.IR message .
.SP
+.BI "disabled-address-family " afam
+(For
+.B ADD
+and
+.BR PORT .)
+The address family
+.I afam
+is supported, but was disabled using command-line arguments.
+.SP
.BI "invalid-port " number
(For
.BR ADD .)
.BI "invalid-port " number
(For
.BR ADD .)
.SH "SYNOPSIS"
.
.B tripe
.SH "SYNOPSIS"
.
.B tripe
.RB [ \-d
.IR dir ]
.RB [ \-b
.RB [ \-d
.IR dir ]
.RB [ \-b
per line, and exits with status 0. This is intended for the use of the
start-up script, so that it can check that it will actually work.
.TP
per line, and exits with status 0. This is intended for the use of the
start-up script, so that it can check that it will actually work.
.TP
+.B "\-4, \-\-ipv4"
+Use only IPv4 addresses. The server will resolve names only to IPv4
+addresses, and not attempt to create IPv6 sockets.
+.TP
+.B "\-6, \-\-ipv6"
+Use only IPv6 addresses. The server will resolve names only to IPv6
+addresses, and not attempt to create IPv4 sockets. Note that v6-mapped
+IPv4 addresses won't work either.
+.TP
.B "\-D, \-\-daemon"
Dissociates from its terminal and starts running in the background after
completing the initialization procedure described above. If running as
.B "\-D, \-\-daemon"
Dissociates from its terminal and starts running in the background after
completing the initialization procedure described above. If running as
-u, --usage Display pointless usage message.\n\
--tunnels Display IP tunnel drivers and exit.\n\
\n\
-u, --usage Display pointless usage message.\n\
--tunnels Display IP tunnel drivers and exit.\n\
\n\
+-4, --ipv4 Transport over IPv4 only.\n\
+-6, --ipv6 Transport over IPv6 only.\n\
-D, --daemon Run in the background.\n\
-F, --foreground Quit when stdin reports end-of-file.\n\
-d, --directory=DIR Switch to directory DIR [default " CONFIGDIR "].\n\
-D, --daemon Run in the background.\n\
-F, --foreground Quit when stdin reports end-of-file.\n\
-d, --directory=DIR Switch to directory DIR [default " CONFIGDIR "].\n\
if ((p = getenv("TRIPESOCK")) != 0)
csock = p;
tun_default = tunnels[0];
if ((p = getenv("TRIPESOCK")) != 0)
csock = p;
tun_default = tunnels[0];
- aihint.ai_family = AF_INET;
+ aihint.ai_family = AF_UNSPEC;
for (;;) {
static const struct option opts[] = {
for (;;) {
static const struct option opts[] = {
{ "usage", 0, 0, 'u' },
{ "tunnels", 0, 0, '0' },
{ "usage", 0, 0, 'u' },
{ "tunnels", 0, 0, '0' },
+ { "ipv4", 0, 0, '4' },
+ { "ipv6", 0, 0, '6' },
{ "daemon", 0, 0, 'D' },
{ "foreground", 0, 0, 'F' },
{ "uid", OPTF_ARGREQ, 0, 'U' },
{ "daemon", 0, 0, 'D' },
{ "foreground", 0, 0, 'F' },
{ "uid", OPTF_ARGREQ, 0, 'U' },
- i = mdwopt(argc, argv, "hvuDFU:G:b:n:p:d:k:K:t:a:m:" T("T:"),
+ i = mdwopt(argc, argv, "hvu46DFU:G:b:n:p:d:k:K:t:a:m:" T("T:"),
opts, 0, 0, 0);
if (i < 0)
break;
opts, 0, 0, 0);
if (i < 0)
break;
+ case '4':
+ aihint.ai_family = AF_INET;
+ break;
+ case '6':
+ aihint.ai_family = AF_INET6;
+ break;
case 'D':
f |= f_daemon;
break;
case 'D':
f |= f_daemon;
break;
/* --- The address-family table --- */
#define ADDRFAM(_) \
/* --- The address-family table --- */
#define ADDRFAM(_) \
+ _(INET, want_ipv4) \
+ _(INET6, want_ipv6)
enum {
#define ENUM(af, qf) AFIX_##af,
enum {
#define ENUM(af, qf) AFIX_##af,
typedef union addr {
struct sockaddr sa;
struct sockaddr_in sin;
typedef union addr {
struct sockaddr sa;
struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
} addr;
/* --- Mapping keyed on addresses --- */
} addr;
/* --- Mapping keyed on addresses --- */
peer=$1 ifname=$2 family=$3; shift 3
## Parse the address family.
peer=$1 ifname=$2 family=$3; shift 3
## Parse the address family.
+case "$family" in
+ INET) ipsz=20 ;;
+ INET6) ipsz=40 ;;
+ *) echo >&2 "$0: unknown address family $family"; exit 1 ;;
+esac
- INET,1) addr=$1 port=4070 ;;
- INET,2) addr=$1 port=$2 ;;
- INET,*) echo >&2 "$0: bad INET address"; exit 1 ;;
- *) echo >&2 "$0: unknown address family $family"; exit 1 ;;
+ INET,1 | INET6,1) addr=$1 port=4070 ;;
+ INET,2 | INET6,2) addr=$1 port=$2 ;;
+ INET,* | INET6,*) echo >&2 "$0: bad $family address"; exit 1 ;;
+ *) echo >&2 "$0: unknown address family $family"; exit 1 ;;
esac
###--------------------------------------------------------------------------
esac
###--------------------------------------------------------------------------
mtu=$P_MTU;;
*)
pathmtu=$(pathmtu "$addr")
mtu=$P_MTU;;
*)
pathmtu=$(pathmtu "$addr")
- mtu=$(expr "$pathmtu" - 29 - $A_BULK_OVERHEAD)
+ mtu=$(( $pathmtu - $ipsz - 9 - $A_BULK_OVERHEAD ))
;;
esac
try ip link set dev "$ifname" up mtu "$mtu"
;;
esac
try ip link set dev "$ifname" up mtu "$mtu"