Skip to content

Instantly share code, notes, and snippets.

@kaechele
Created November 7, 2018 19:41
Show Gist options
  • Save kaechele/3fbfcc38d5ef509d02bca3251a72cf44 to your computer and use it in GitHub Desktop.
Save kaechele/3fbfcc38d5ef509d02bca3251a72cf44 to your computer and use it in GitHub Desktop.
TD v6 Client
diff --git a/client/l2tp_client.c b/client/l2tp_client.c
index 16fdf3c..6ea2aae 100644
--- a/client/l2tp_client.c
+++ b/client/l2tp_client.c
@@ -65,6 +65,7 @@
// Overhead of IP and UDP headers for measuring PMTU.
#define IPV4_HDR_OVERHEAD 28
+#define IPV6_HDR_OVERHEAD 48
// L2TP data header overhead for calculating tunnel MTU; takes
// the following headers into account:
@@ -176,7 +177,7 @@ typedef struct {
// External hook script.
char *hook;
// Local IP endpoint.
- struct sockaddr_in local_endpoint;
+ struct addrinfo *local_endpoint;
// Broker hostname.
char *broker_hostname;
// Broker port (or service name).
@@ -360,7 +361,7 @@ void put_u32(char **buffer, uint32_t value)
(*buffer) += sizeof(value);
}
-l2tp_context *context_new(char *uuid, const char *local_ip, const char *broker_hostname,
+l2tp_context *context_new(char *uuid, const char *local_addr, const char *broker_hostname,
char *broker_port, char *tunnel_iface, char *bind_iface, char *hook, int tunnel_id, int limit_bandwidth_down)
{
l2tp_context *ctx = (l2tp_context*) calloc(1, sizeof(l2tp_context));
@@ -371,11 +372,17 @@ l2tp_context *context_new(char *uuid, const char *local_ip, const char *broker_h
ctx->state = STATE_REINIT;
- ctx->local_endpoint.sin_family = AF_INET;
- ctx->local_endpoint.sin_port = 0;
- if (inet_aton(local_ip, &ctx->local_endpoint.sin_addr) < 0) {
- syslog(LOG_ERR, "Failed to parse local endpoint!");
- goto free_and_return;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_DGRAM;
+ hints.ai_protocol = 0;
+ hints.ai_flags = AI_PASSIVE|AI_ADDRCONFIG;
+ struct addrinfo* res = 0;
+ int err = getaddrinfo(local_addr, 0, &hints, &ctx->local_endpoint);
+ if (err) {
+ syslog(LOG_ERR, "Failed to parse or resolve local endpoint! (err=%d/%s)", err, gai_strerror(err));
+ goto free_and_return;
}
ctx->broker_hostname = strdup(broker_hostname);
@@ -421,9 +428,11 @@ int context_reinitialize(l2tp_context *ctx)
// because other functions than the state machine call this function.
ctx->state = STATE_REINIT;
+ struct addrinfo *local_endpoint = ctx->local_endpoint;
+
if (ctx->fd > 0)
close(ctx->fd);
- ctx->fd = socket(AF_INET, SOCK_DGRAM, 0);
+ ctx->fd = socket(local_endpoint->ai_family, local_endpoint->ai_socktype, local_endpoint->ai_protocol);
if (ctx->fd < 0)
return -1;
@@ -438,8 +447,9 @@ int context_reinitialize(l2tp_context *ctx)
}
}
- if (bind(ctx->fd, (struct sockaddr*) &ctx->local_endpoint, sizeof(ctx->local_endpoint)) < 0) {
- syslog(LOG_ERR, "Failed to bind to local endpoint - check WAN connectivity!");
+ int err = bind(ctx->fd, local_endpoint->ai_addr, local_endpoint->ai_addrlen);
+ if (err < 0) {
+ syslog(LOG_ERR, "Failed to bind to local endpoint - check WAN connectivity! (err=%s (%d))", strerror(err), err);
return -1;
}
@@ -491,10 +501,16 @@ void context_start_connect(l2tp_context *ctx)
if (ctx->state != STATE_RESOLVING)
return;
+ char *broker_host = ctx->broker_hostname;
+ // If this is an IPv6 address we need to cut off the brackets
+ if(broker_host[0] == '[') {
+ broker_host++[strlen(broker_host)] = 0;;
+ }
+
memset(&ctx->broker_reshints, 0, sizeof(struct addrinfo));
- ctx->broker_reshints.ai_family = AF_INET;
+ ctx->broker_reshints.ai_family = AF_UNSPEC;
ctx->broker_reshints.ai_socktype = SOCK_DGRAM;
- ctx->broker_resq = asyncns_getaddrinfo(asyncns_context, ctx->broker_hostname, ctx->broker_port,
+ ctx->broker_resq = asyncns_getaddrinfo(asyncns_context, broker_host, ctx->broker_port,
&ctx->broker_reshints);
ctx->timer_resolving = timer_now();
@@ -543,9 +559,9 @@ void context_setup_limits(l2tp_context *ctx)
void context_process_control_packet(l2tp_context *ctx)
{
char buffer[2048];
- struct sockaddr_in endpoint;
+ struct sockaddr_in6 endpoint;
socklen_t endpoint_len = sizeof(endpoint);
- ssize_t bytes = recvfrom(ctx->fd, &buffer, sizeof(buffer), 0, (struct sockaddr*) &endpoint,
+ ssize_t bytes = recvfrom(ctx->fd, &buffer, sizeof(buffer), 0, (struct sockaddr_in6*) &endpoint,
&endpoint_len);
// A valid package must at least 6 byte long.
@@ -661,7 +677,9 @@ void context_process_control_packet(l2tp_context *ctx)
if (payload_length != 2)
break;
// Process a PMTU probe.
- uint16_t psize = parse_u16(&buf) + IPV4_HDR_OVERHEAD;
+ struct addrinfo *local_endpoint = ctx->local_endpoint;
+ int overhead = local_endpoint->ai_family == AF_INET6 ? IPV4_HDR_OVERHEAD : IPV6_HDR_OVERHEAD;
+ uint16_t psize = parse_u16(&buf) + overhead;
if (psize > ctx->probed_pmtu)
ctx->probed_pmtu = psize;
}
@@ -815,7 +833,9 @@ void context_send_pmtu_probe(l2tp_context *ctx, size_t size)
put_u8(&buf, 0);
// Send the packet.
- if (send(ctx->fd, &buffer, size - IPV4_HDR_OVERHEAD, 0) < 0) {
+ struct addrinfo *local_endpoint = ctx->local_endpoint;
+ int overhead = local_endpoint->ai_family == AF_INET6 ? IPV4_HDR_OVERHEAD : IPV6_HDR_OVERHEAD;
+ if (send(ctx->fd, &buffer, size - overhead, 0) < 0) {
switch (errno) {
// Sometimes EAFNOSUPPORT is emitted for messages larger than the local MTU in case of PPPoE.
case EAFNOSUPPORT:
@@ -1264,6 +1284,7 @@ void context_free(l2tp_context *ctx)
free(ctx->broker_hostname);
free(ctx->broker_port);
free(ctx->bind_iface);
+ freeaddrinfo(ctx->local_endpoint);
free(ctx);
}
@@ -1317,7 +1338,7 @@ int main(int argc, char **argv)
// Parse program options.
int log_option = 0;
- char *uuid = NULL, *local_ip = "0.0.0.0", *tunnel_iface = NULL, *bind_iface_opt = NULL;
+ char *uuid = NULL, *local_ip = "::", *tunnel_iface = NULL, *bind_iface_opt = NULL;
char *hook = NULL;
unsigned int tunnel_id = 1;
int limit_bandwidth_down = 0;
@@ -1346,7 +1367,7 @@ int main(int argc, char **argv)
return 1;
}
- char *pos = strchr(optarg, ':');
+ char *pos = strrchr(optarg, ':');
if (!pos) {
fprintf(stderr, "ERROR: Each broker must be passed in the format 'host:port'!\n");
return 1;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment