From 640efd7b86c6c0db7570e9678a4b9a4c32540955 Mon Sep 17 00:00:00 2001 From: Nick Peng Date: Sun, 8 Sep 2019 13:50:54 +0800 Subject: [PATCH] Fix tcp local address issue --- src/dns_server.c | 2 +- src/util.c | 42 ++++++++++++++++++++++++++++++++++++++++++ src/util.h | 2 ++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/src/dns_server.c b/src/dns_server.c index 26cae60..6788b6c 100644 --- a/src/dns_server.c +++ b/src/dns_server.c @@ -2342,7 +2342,7 @@ static int _dns_server_tcp_accept(struct dns_server_conn_tcp_server *tcpserver, return -1; } - if (getsockname(tcpclient->head.fd, (struct sockaddr *)&tcpclient->localaddr, &tcpclient->localaddr_len) != 0) { + if (getsocknet_inet(tcpclient->head.fd, (struct sockaddr *)&tcpclient->localaddr, &tcpclient->localaddr_len) != 0) { tlog(TLOG_ERROR, "get local addr failed, %s", strerror(errno)); goto errout; } diff --git a/src/util.c b/src/util.c index caec052..86caab6 100644 --- a/src/util.c +++ b/src/util.c @@ -140,6 +140,48 @@ errout: return -1; } +int getsocknet_inet(int fd, struct sockaddr *addr, socklen_t *addr_len) +{ + struct sockaddr_storage addr_store; + socklen_t addr_store_len = sizeof(addr_store); + if (getsockname(fd, (struct sockaddr *)&addr_store, &addr_store_len) != 0) { + goto errout; + } + + switch (addr_store.ss_family) { + case AF_INET: { + struct sockaddr_in *addr_in; + addr_in = (struct sockaddr_in *)addr; + addr_in->sin_family = AF_INET; + *addr_len = sizeof(struct sockaddr_in); + memcpy(addr, addr_in, sizeof(struct sockaddr_in)); + } break; + case AF_INET6: { + struct sockaddr_in6 *addr_in6; + addr_in6 = (struct sockaddr_in6 *)addr; + if (IN6_IS_ADDR_V4MAPPED(&addr_in6->sin6_addr)) { + struct sockaddr_in addr_in4; + memset(&addr_in4, 0, sizeof(addr_in4)); + memcpy(&addr_in4.sin_addr.s_addr, addr_in6->sin6_addr.s6_addr + 12, sizeof(addr_in4.sin_addr.s_addr)); + addr_in4.sin_family = AF_INET; + addr_in4.sin_port = 0; + *addr_len = sizeof(struct sockaddr_in); + memcpy(addr, &addr_in4, sizeof(struct sockaddr_in)); + } else { + addr_in6->sin6_family = AF_INET6; + *addr_len = sizeof(struct sockaddr_in6); + memcpy(addr, addr_in6, sizeof(struct sockaddr_in6)); + } + } break; + default: + goto errout; + break; + } + return 0; +errout: + return -1; +} + int fill_sockaddr_by_ip(unsigned char *ip, int ip_len, int port, struct sockaddr *addr, socklen_t *addr_len) { if (ip == NULL || addr == NULL || addr_len == NULL) { diff --git a/src/util.h b/src/util.h index 80cd5cd..ee670f9 100644 --- a/src/util.h +++ b/src/util.h @@ -20,6 +20,8 @@ char *gethost_by_addr(char *host, int maxsize, struct sockaddr *addr); int getaddr_by_host(char *host, struct sockaddr *addr, socklen_t *addr_len); +int getsocknet_inet(int fd, struct sockaddr *addr, socklen_t *addr_len); + int fill_sockaddr_by_ip(unsigned char *ip, int ip_len, int port, struct sockaddr *addr, socklen_t *addr_len); int parse_ip(const char *value, char *ip, int *port);