diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2021-03-17 21:00:16 +0000 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2021-03-17 21:00:16 +0000 |
commit | 43930496beb307813f77ec97577f028db8891b1c (patch) | |
tree | df156c301b93596d247b15726102ce8f3e4247eb | |
parent | 84579d030ab42f6d8d462bf2ac1041fff18962d1 (diff) | |
parent | 666235c02866039536cdd535c36e8d0fd29dde93 (diff) | |
download | slirp-43930496beb307813f77ec97577f028db8891b1c.zip slirp-43930496beb307813f77ec97577f028db8891b1c.tar.gz slirp-43930496beb307813f77ec97577f028db8891b1c.tar.bz2 |
Merge branch 'hostxfwd' into 'master'
Add ipv4/ipv6-agnostic host forwarding functions
See merge request slirp/libslirp!75
-rw-r--r-- | src/libslirp.h | 12 | ||||
-rw-r--r-- | src/libslirp.map | 2 | ||||
-rw-r--r-- | src/slirp.c | 72 |
3 files changed, 85 insertions, 1 deletions
diff --git a/src/libslirp.h b/src/libslirp.h index b52b63d..a0f0eb1 100644 --- a/src/libslirp.h +++ b/src/libslirp.h @@ -8,6 +8,7 @@ #ifdef _WIN32 #include <winsock2.h> +#include <ws2tcpip.h> #include <in6addr.h> #else #include <netinet/in.h> @@ -166,7 +167,16 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, int host_port, struct in_addr guest_addr, int guest_port); int slirp_remove_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, int host_port); -/* TODO: rather introduce a function that takes two sockaddr */ + +#define SLIRP_HOSTFWD_UDP 1 +int slirp_add_hostxfwd(Slirp *slirp, + const struct sockaddr *haddr, socklen_t haddrlen, + const struct sockaddr *gaddr, socklen_t gaddrlen, + int flags); +int slirp_remove_hostxfwd(Slirp *slirp, + const struct sockaddr *haddr, socklen_t haddrlen, + int flags); + int slirp_add_ipv6_hostfwd(Slirp *slirp, int is_udp, struct in6_addr host_addr, int host_port, struct in6_addr guest_addr, int guest_port); diff --git a/src/libslirp.map b/src/libslirp.map index 20a17ac..cae6cf8 100644 --- a/src/libslirp.map +++ b/src/libslirp.map @@ -30,6 +30,8 @@ SLIRP_4.2 { } SLIRP_4.1; SLIRP_4.5 { + slirp_add_hostxfwd; + slirp_remove_hostxfwd; slirp_add_ipv6_hostfwd; slirp_remove_ipv6_hostfwd; slirp_neighbor_info; diff --git a/src/slirp.c b/src/slirp.c index 110e6fc..98cfd48 100644 --- a/src/slirp.c +++ b/src/slirp.c @@ -1141,6 +1141,78 @@ int slirp_add_hostfwd(Slirp *slirp, int is_udp, struct in_addr host_addr, return 0; } +int slirp_remove_hostxfwd(Slirp *slirp, + const struct sockaddr *haddr, socklen_t haddrlen, + int flags) +{ + struct socket *so; + struct socket *head = (flags & SLIRP_HOSTFWD_UDP ? &slirp->udb : &slirp->tcb); + struct sockaddr_storage addr; + socklen_t addr_len; + + for (so = head->so_next; so != head; so = so->so_next) { + addr_len = sizeof(addr); + if ((so->so_state & SS_HOSTFWD) && + getsockname(so->s, (struct sockaddr *)&addr, &addr_len) == 0 && + sockaddr_equal(&addr, (const struct sockaddr_storage *) haddr)) { + so->slirp->cb->unregister_poll_fd(so->s, so->slirp->opaque); + closesocket(so->s); + sofree(so); + return 0; + } + } + + return -1; +} + +int slirp_add_hostxfwd(Slirp *slirp, + const struct sockaddr *haddr, socklen_t haddrlen, + const struct sockaddr *gaddr, socklen_t gaddrlen, + int flags) +{ + struct sockaddr_in gdhcp_addr; + if (gaddr->sa_family == AF_INET) { + const struct sockaddr_in *gaddr_in = (const struct sockaddr_in *) gaddr; + + if (gaddrlen < sizeof(struct sockaddr_in)) + return -1; + + if (!gaddr_in->sin_addr.s_addr) { + gdhcp_addr = *gaddr_in; + gdhcp_addr.sin_addr = slirp->vdhcp_startaddr; + gaddr = (struct sockaddr *) &gdhcp_addr; + gaddrlen = sizeof(gdhcp_addr); + } + } else { + const struct sockaddr_in6 *gaddr_in6 = (const struct sockaddr_in6 *) gaddr; + + if (gaddrlen < sizeof(struct sockaddr_in6)) + return -1; + + if (in6_zero(&gaddr_in6->sin6_addr)) { + /* + * Libslirp currently only provides a stateless DHCPv6 server, thus + * we can't translate "addr-any" to the guest. Instead, for now, + * reject it. + */ + return -1; + } + } + + if (flags & SLIRP_HOSTFWD_UDP) { + if (!udpx_listen(slirp, haddr, haddrlen, + gaddr, gaddrlen, + SS_HOSTFWD)) + return -1; + } else { + if (!tcpx_listen(slirp, haddr, haddrlen, + gaddr, gaddrlen, + SS_HOSTFWD)) + return -1; + } + return 0; +} + int slirp_remove_ipv6_hostfwd(Slirp *slirp, int is_udp, struct in6_addr host_addr, int host_port) { |