aboutgitcodebugslistschat
diff options
context:
space:
mode:
-rw-r--r--inany.h30
-rw-r--r--tcp.c67
2 files changed, 59 insertions, 38 deletions
diff --git a/inany.h b/inany.h
index 03e3e3f..52d43f2 100644
--- a/inany.h
+++ b/inany.h
@@ -30,11 +30,11 @@ union inany_addr {
*
* Return: IPv4 address if @addr is IPv4, NULL otherwise
*/
-static inline const struct in_addr *inany_v4(const union inany_addr *addr)
+static inline struct in_addr *inany_v4(const union inany_addr *addr)
{
if (!IN6_IS_ADDR_V4MAPPED(&addr->a6))
return NULL;
- return &addr->v4mapped.a4;
+ return (struct in_addr *)&addr->v4mapped.a4;
}
/** inany_equals - Compare two IPv[46] addresses
@@ -66,3 +66,29 @@ static inline void inany_from_af(union inany_addr *aa, int af, const void *addr)
assert(0);
}
}
+
+/** inany_from_sockaddr - Extract IPv[46] address and port number from sockaddr
+ * @aa: Pointer to store IPv[46] address
+ * @port: Pointer to store port number, host order
+ * @addr: struct sockaddr_in (IPv4) or struct sockaddr_in6 (IPv6)
+ */
+static inline void inany_from_sockaddr(union inany_addr *aa, in_port_t *port,
+ const void *addr)
+{
+ const struct sockaddr *sa = (const struct sockaddr *)addr;
+
+ if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
+
+ inany_from_af(aa, AF_INET6, &sa6->sin6_addr);
+ *port = ntohs(sa6->sin6_port);
+ } else if (sa->sa_family == AF_INET) {
+ struct sockaddr_in *sa4 = (struct sockaddr_in *)sa;
+
+ inany_from_af(aa, AF_INET, &sa4->sin_addr);
+ *port = ntohs(sa4->sin_port);
+ } else {
+ /* Not valid to call with other address families */
+ assert(0);
+ }
+}
diff --git a/tcp.c b/tcp.c
index 7d5ac6c..59c1a93 100644
--- a/tcp.c
+++ b/tcp.c
@@ -2725,6 +2725,34 @@ static void tcp_connect_finish(struct ctx *c, struct tcp_tap_conn *conn)
}
/**
+ * tcp_snat_inbound() - Translate source address for inbound data if needed
+ * @c: Execution context
+ * @addr: Source address of inbound packet/connection
+ */
+static void tcp_snat_inbound(const struct ctx *c, union inany_addr *addr)
+{
+ struct in_addr *addr4 = inany_v4(addr);
+
+ if (addr4) {
+ if (IN4_IS_ADDR_LOOPBACK(addr4) ||
+ IN4_IS_ADDR_UNSPECIFIED(addr4) ||
+ IN4_ARE_ADDR_EQUAL(addr4, &c->ip4.addr_seen))
+ *addr4 = c->ip4.gw;
+ } else {
+ struct in6_addr *addr6 = &addr->a6;
+
+ if (IN6_IS_ADDR_LOOPBACK(addr6) ||
+ IN6_ARE_ADDR_EQUAL(addr6, &c->ip6.addr_seen) ||
+ IN6_ARE_ADDR_EQUAL(addr6, &c->ip6.addr)) {
+ if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
+ *addr6 = c->ip6.gw;
+ else
+ *addr6 = c->ip6.addr_ll;
+ }
+ }
+}
+
+/**
* tcp_tap_conn_from_sock() - Initialize state for non-spliced connection
* @c: Execution context
* @ref: epoll reference of listening socket
@@ -2744,43 +2772,10 @@ static void tcp_tap_conn_from_sock(struct ctx *c, union epoll_ref ref,
conn->ws_to_tap = conn->ws_from_tap = 0;
conn_event(c, conn, SOCK_ACCEPTED);
- if (sa->sa_family == AF_INET6) {
- struct sockaddr_in6 sa6;
-
- memcpy(&sa6, sa, sizeof(sa6));
+ inany_from_sockaddr(&conn->addr, &conn->sock_port, sa);
+ conn->tap_port = ref.r.p.tcp.tcp.index;
- if (IN6_IS_ADDR_LOOPBACK(&sa6.sin6_addr) ||
- IN6_ARE_ADDR_EQUAL(&sa6.sin6_addr, &c->ip6.addr_seen) ||
- IN6_ARE_ADDR_EQUAL(&sa6.sin6_addr, &c->ip6.addr)) {
- struct in6_addr *src;
-
- if (IN6_IS_ADDR_LINKLOCAL(&c->ip6.gw))
- src = &c->ip6.gw;
- else
- src = &c->ip6.addr_ll;
-
- memcpy(&sa6.sin6_addr, src, sizeof(*src));
- }
-
- inany_from_af(&conn->addr, AF_INET6, &sa6.sin6_addr);
-
- conn->sock_port = ntohs(sa6.sin6_port);
- conn->tap_port = ref.r.p.tcp.tcp.index;
- } else {
- struct sockaddr_in sa4;
-
- memcpy(&sa4, sa, sizeof(sa4));
-
- if (IN4_IS_ADDR_LOOPBACK(&sa4.sin_addr) ||
- IN4_IS_ADDR_UNSPECIFIED(&sa4.sin_addr) ||
- IN4_ARE_ADDR_EQUAL(&sa4.sin_addr, &c->ip4.addr_seen))
- sa4.sin_addr = c->ip4.gw;
-
- inany_from_af(&conn->addr, AF_INET, &sa4.sin_addr);
-
- conn->sock_port = ntohs(sa4.sin_port);
- conn->tap_port = ref.r.p.tcp.tcp.index;
- }
+ tcp_snat_inbound(c, &conn->addr);
tcp_seq_init(c, conn, now);
tcp_hash_insert(c, conn);