diff --git a/api.c b/api.c index c58e0c4..0ba2305 100644 --- a/api.c +++ b/api.c @@ -41,9 +41,13 @@ int api_bindlisten(const char *api_socket) struct api_hostfwd { int id; int is_udp; + int is_ipv4; + int is_ipv6; struct in_addr host_addr; + struct in6_addr host_addr6; int host_port; struct in_addr guest_addr; + struct in6_addr guest_addr6; int guest_port; }; @@ -99,17 +103,19 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, const char *proto_s = json_object_dotget_string(jo, "arguments.proto"); const char *host_addr_s = json_object_dotget_string(jo, "arguments.host_addr"); + char *host_addr6_s = NULL; const char *guest_addr_s = json_object_dotget_string(jo, "arguments.guest_addr"); + char *guest_addr6_s = NULL; struct api_hostfwd *fwd = g_malloc0(sizeof(*fwd)); if (fwd == NULL) { perror("fatal: malloc"); exit(EXIT_FAILURE); } fwd->is_udp = -1; /* TODO: support SCTP */ - if (strcmp(proto_s, "udp") == 0) { + if (strncmp(proto_s, "udp", 3) == 0) { fwd->is_udp = 1; - } else if (strcmp(proto_s, "tcp") == 0) { + } else if (strncmp(proto_s, "tcp", 3) == 0) { fwd->is_udp = 0; } if (fwd->is_udp == -1) { @@ -119,16 +125,26 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, free(fwd); goto finish; } - if (host_addr_s == NULL || host_addr_s[0] == '\0') { - host_addr_s = "0.0.0.0"; - } - if (inet_pton(AF_INET, host_addr_s, &fwd->host_addr) != 1) { - const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " - "bad arguments.host_addr\"}}"; - wrc = write(fd, err, strlen(err)); - free(fwd); - goto finish; + int flags = (fwd->is_udp ? SLIRP_HOSTFWD_UDP : 0); + + if (strlen(proto_s) == 4) { + if (proto_s[3] == '4') { + fwd->is_ipv4 = 1; + } else if (proto_s[3] == '6') { + fwd->is_ipv6 = 1; + } else { + const char *err = + "{\"error\":{\"desc\":\"bad request: add_hostfwd: " + "bad arguments.proto\"}}"; + wrc = write(fd, err, strlen(err)); + free(fwd); + goto finish; + } + } else { + fwd->is_ipv4 = 1; + fwd->is_ipv6 = 1; } + fwd->host_port = (int)json_object_dotget_number(jo, "arguments.host_port"); if (fwd->host_port == 0) { const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " @@ -137,16 +153,6 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, free(fwd); goto finish; } - - if (guest_addr_s == NULL || guest_addr_s[0] == '\0') { - fwd->guest_addr = ctx->cfg->recommended_vguest; - } else if (inet_pton(AF_INET, guest_addr_s, &fwd->guest_addr) != 1) { - const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " - "bad arguments.guest_addr\"}}"; - wrc = write(fd, err, strlen(err)); - free(fwd); - goto finish; - } fwd->guest_port = (int)json_object_dotget_number(jo, "arguments.guest_port"); if (fwd->guest_port == 0) { @@ -156,13 +162,92 @@ static int api_handle_req_add_hostfwd(Slirp *slirp, int fd, struct api_ctx *ctx, free(fwd); goto finish; } - if (slirp_add_hostfwd(slirp, fwd->is_udp, fwd->host_addr, fwd->host_port, - fwd->guest_addr, fwd->guest_port) < 0) { - const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " - "slirp_add_hostfwd failed\"}}"; - wrc = write(fd, err, strlen(err)); - free(fwd); - goto finish; + + if (fwd->is_ipv4) { + if (guest_addr_s == NULL || guest_addr_s[0] == '\0') { + fwd->guest_addr = ctx->cfg->recommended_vguest; + } else if (inet_pton(AF_INET, guest_addr_s, &fwd->guest_addr) != 1) { + const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " + "bad arguments.guest_addr\"}}"; + wrc = write(fd, err, strlen(err)); + free(fwd); + goto finish; + } + if (host_addr_s == NULL || host_addr_s[0] == '\0') { + host_addr_s = "0.0.0.0"; + } + if (inet_pton(AF_INET, host_addr_s, &fwd->host_addr) != 1) { + const char *err = + "{\"error\":{\"desc\":\"bad request: add_hostfwd: " + "bad arguments.host_addr\"}}"; + wrc = write(fd, err, strlen(err)); + free(fwd); + goto finish; + } + struct sockaddr_in host; + memset(&host, 0, sizeof(host)); + host.sin_family = AF_INET; + host.sin_addr.s_addr = fwd->host_addr.s_addr; + host.sin_port = htons(fwd->host_port); + struct sockaddr_in guest; + memset(&guest, 0, sizeof(guest)); + guest.sin_family = AF_INET; + guest.sin_addr.s_addr = fwd->guest_addr.s_addr; + guest.sin_port = htons(fwd->guest_port); + if (slirp_add_hostxfwd(slirp, + (const struct sockaddr*)&host, sizeof(host), + (const struct sockaddr*)&guest, sizeof(guest), flags) < 0) { + const char *err = + "{\"error\":{\"desc\":\"bad request: add_hostfwd: " + "slirp_add_hostxfwd failed\"}}"; + wrc = write(fd, err, strlen(err)); + free(fwd); + goto finish; + } + } + if (fwd->is_ipv6) { + if (guest_addr_s == NULL || guest_addr_s[0] == '\0') { + guest_addr_s = "fd00::100"; + } + if (inet_pton(AF_INET6, guest_addr_s, &fwd->guest_addr6) != 1) { + const char *err = "{\"error\":{\"desc\":\"bad request: add_hostfwd: " + "bad arguments.guest_addr\"}}"; + wrc = write(fd, err, strlen(err)); + free(fwd); + goto finish; + } + if (host_addr_s == NULL || host_addr_s[0] == '\0' || + strcmp(host_addr_s, "0.0.0.0") == 0) { + host_addr_s = "::"; + } + if (inet_pton(AF_INET6, host_addr_s, &fwd->host_addr6) != 1) { + const char *err = + "{\"error\":{\"desc\":\"bad request: add_hostfwd: " + "bad arguments.host_addr\"}}"; + wrc = write(fd, err, strlen(err)); + free(fwd); + goto finish; + } + struct sockaddr_in6 host; + memset(&host, 0, sizeof(host)); + host.sin6_family = AF_INET6; + host.sin6_addr = fwd->host_addr6; + host.sin6_port = htons(fwd->host_port); + struct sockaddr_in6 guest; + memset(&guest, 0, sizeof(guest)); + guest.sin6_family = AF_INET6; + guest.sin6_addr = fwd->guest_addr6; + guest.sin6_port = htons(fwd->guest_port); + if (slirp_add_hostxfwd(slirp, + (const struct sockaddr*)&host, sizeof(host), + (const struct sockaddr*)&guest, sizeof(guest), flags) < 0) { + const char *err = + "{\"error\":{\"desc\":\"bad request: add_hostfwd: " + "slirp_add_hostfwd failed\"}}"; + wrc = write(fd, err, strlen(err)); + free(fwd); + goto finish; + } } fwd->id = ctx->hostfwds_nextid; ctx->hostfwds_nextid++; diff --git a/main.c b/main.c index 1844c59..f21867c 100644 --- a/main.c +++ b/main.c @@ -205,6 +205,58 @@ static int configure_network(const char *tapname, return 0; } +struct in6_ifreq { + struct in6_addr ifr6_addr; + __u32 ifr6_prefixlen; + unsigned int ifr6_ifindex; +}; + +static int configure_network6(const char *tapname, + struct slirp4netns_config *cfg) +{ + struct rtentry route; + struct ifreq ifr; + struct in6_ifreq ifr6; + struct sockaddr_in6 sai; + int sockfd; + + sockfd = socket(AF_INET6, SOCK_DGRAM, 0); + if (sockfd < 0) { + perror("cannot create socket"); + return -1; + } + + memset(&ifr, 0, sizeof(ifr)); + ifr.ifr_flags = IFF_UP | IFF_RUNNING; + strncpy(ifr.ifr_name, tapname, sizeof(ifr.ifr_name) - 1); + + if (ioctl(sockfd, SIOGIFINDEX, &ifr) < 0) { + perror("cannot get dev index"); + return -1; + } + + memset(&sai, 0, sizeof(struct sockaddr)); + sai.sin6_family = AF_INET6; + sai.sin6_port = 0; + + if (inet_pton(AF_INET6, "fd00::100", &sai.sin6_addr) != 1) { + perror("cannot create device address"); + return -1; + } + + memcpy((char *)&ifr6.ifr6_addr, &sai.sin6_addr, sizeof(struct in6_addr)); + + ifr6.ifr6_ifindex = ifr.ifr_ifindex; + ifr6.ifr6_prefixlen = 64; + + if (ioctl(sockfd, SIOCSIFADDR, &ifr6) < 0) { + perror("cannot set device address"); + return -1; + } + + return 0; +} + static int child(int sock, pid_t target_pid, bool do_config_network, const char *tapname, char *netns_path, char *userns_path, struct slirp4netns_config *cfg) @@ -219,6 +271,9 @@ static int child(int sock, pid_t target_pid, bool do_config_network, if (do_config_network && configure_network(tapname, cfg) < 0) { return -1; } + if (do_config_network && configure_network6(tapname, cfg) < 0) { + return -1; + } if (sendfd(sock, tapfd) < 0) { close(tapfd); close(sock);