1#include <stdio.h> 2#include <stdlib.h> 3#include <unistd.h> 4#include <time.h> 5#include <string.h> 6#include <arpa/inet.h> 7 8#ifdef USE_NFCT 9#include <libmnl/libmnl.h> 10#include <libnetfilter_conntrack/libnetfilter_conntrack.h> 11 12#include <linux/netfilter/nf_conntrack_tcp.h> 13 14struct data_cb_s 15{ 16 struct sockaddr_storage * ext; 17 uint8_t found; 18}; 19 20static int data_cb(const struct nlmsghdr *nlh, void *data) 21{ 22 struct nf_conntrack *ct; 23 struct data_cb_s * d = (struct data_cb_s*) data; 24 struct sockaddr_in* ext4 = (struct sockaddr_in*) d->ext; 25 26 ct = nfct_new(); 27 if (ct == NULL) 28 return MNL_CB_OK; 29 nfct_nlmsg_parse(nlh, ct); 30 31 if (data) { 32 ext4->sin_addr.s_addr = nfct_get_attr_u32(ct, ATTR_REPL_IPV4_DST); 33 ext4->sin_port = nfct_get_attr_u16(ct, ATTR_REPL_PORT_DST); 34 } 35 d->found = 1; 36 nfct_destroy(ct); 37 38 return MNL_CB_OK; 39} 40 41int get_nat_ext_addr(struct sockaddr* src, struct sockaddr *dst, uint8_t proto, 42 struct sockaddr_storage* ret_ext) 43{ 44 struct mnl_socket *nl; 45 struct nlmsghdr *nlh; 46 struct nfgenmsg *nfh; 47 char buf[MNL_SOCKET_BUFFER_SIZE]; 48 unsigned int seq, portid; 49 struct nf_conntrack *ct; 50 int ret; 51 struct data_cb_s data; 52 53 if ((!src)&&(!dst)) { 54 return 0; 55 } 56 57 if (src->sa_family != dst->sa_family) { 58 return 0; 59 } 60 61 nl = mnl_socket_open(NETLINK_NETFILTER); 62 if (nl == NULL) { 63// perror("mnl_socket_open"); 64 goto free_nl; 65 } 66 67 if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) { 68// perror("mnl_socket_bind"); 69 goto free_nl; 70 } 71 portid = mnl_socket_get_portid(nl); 72 73 memset(buf, 0, sizeof(buf)); 74 nlh = mnl_nlmsg_put_header(buf); 75 nlh->nlmsg_type = (NFNL_SUBSYS_CTNETLINK << 8) | IPCTNL_MSG_CT_GET; 76 nlh->nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; 77 nlh->nlmsg_seq = seq = time(NULL); 78 79 nfh = mnl_nlmsg_put_extra_header(nlh, sizeof(struct nfgenmsg)); 80 nfh->nfgen_family = src->sa_family; 81 nfh->version = NFNETLINK_V0; 82 nfh->res_id = 0; 83 84 ct = nfct_new(); 85 if (ct == NULL) { 86 goto free_nl; 87 } 88 89 nfct_set_attr_u8(ct, ATTR_L3PROTO, src->sa_family); 90 if (src->sa_family == AF_INET) { 91 struct sockaddr_in *src4 = (struct sockaddr_in *)src; 92 struct sockaddr_in *dst4 = (struct sockaddr_in *)dst; 93 nfct_set_attr_u32(ct, ATTR_IPV4_SRC, src4->sin_addr.s_addr); 94 nfct_set_attr_u32(ct, ATTR_IPV4_DST, dst4->sin_addr.s_addr); 95 nfct_set_attr_u16(ct, ATTR_PORT_SRC, src4->sin_port); 96 nfct_set_attr_u16(ct, ATTR_PORT_DST, dst4->sin_port); 97 } else if (src->sa_family == AF_INET6) { 98 struct sockaddr_in6 *src6 = (struct sockaddr_in6 *)src; 99 struct sockaddr_in6 *dst6 = (struct sockaddr_in6 *)dst; 100 nfct_set_attr(ct, ATTR_IPV6_SRC, &src6->sin6_addr); 101 nfct_set_attr(ct, ATTR_IPV6_DST, &dst6->sin6_addr); 102 nfct_set_attr_u16(ct, ATTR_PORT_SRC, src6->sin6_port); 103 nfct_set_attr_u16(ct, ATTR_PORT_DST, dst6->sin6_port); 104 } 105 nfct_set_attr_u8(ct, ATTR_L4PROTO, proto); 106 107 nfct_nlmsg_build(nlh, ct); 108 109 ret = mnl_socket_sendto(nl, nlh, nlh->nlmsg_len); 110 if (ret == -1) { 111 goto free_ct; 112 } 113 114 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 115 data.ext = ret_ext; 116 data.found = 0; 117 while (ret > 0) { 118 ret = mnl_cb_run(buf, ret, seq, portid, data_cb, &data); 119 if (ret <= MNL_CB_STOP) 120 break; 121 ret = mnl_socket_recvfrom(nl, buf, sizeof(buf)); 122 } 123 124free_ct: 125 nfct_destroy(ct); 126free_nl: 127 mnl_socket_close(nl); 128 129 return data.found; 130} 131 132#else 133#define DST "dst=" 134#define DST_PORT "dport=" 135#define SRC "src=" 136#define SRC_PORT "sport=" 137#define IP_CONNTRACK_LOCATION "/proc/net/ip_conntrack" 138#define NF_CONNTRACK_LOCATION "/proc/net/nf_conntrack" 139 140int get_nat_ext_addr(struct sockaddr* src, struct sockaddr *dst, uint8_t proto, 141 struct sockaddr_storage* ret_ext) 142{ 143 FILE *f; 144 int af; 145 146 if (!src) 147 return -2; 148 149 af = src->sa_family; 150 151 if ((f = fopen(NF_CONNTRACK_LOCATION, "r")) == NULL) { 152 if ((f = fopen(IP_CONNTRACK_LOCATION, "r")) == NULL) { 153 printf("could not read info about connections from the kernel, " 154 "make sure netfilter is enabled in kernel or by modules.\n"); 155 return -1; 156 } 157 } 158 159 while (!feof(f)) { 160 char line[256], *str; 161 memset(line, 0, sizeof(line)); 162 str = fgets(line, sizeof(line), f); 163 if (line[0] != 0) { 164 char *token, *saveptr; 165 int j; 166 uint8_t src_f, src_port_f, dst_f, dst_port_f; 167 src_f=src_port_f=dst_f=dst_port_f=0; 168 169 for (j = 1; ; j++, str = NULL) { 170 token = strtok_r(str, " ", &saveptr); 171 if (token == NULL) 172 break; 173 174 if ((j==2)&&(af!=atoi(token))) 175 break; 176 if ((j==4)&&(proto!=atoi(token))) 177 break; 178 if (j<=4) 179 continue; 180 181 if (strncmp(token, SRC, sizeof(SRC) - 1) == 0) { 182 char *srcip = token + sizeof(SRC) - 1; 183 uint32_t buf[4]; 184 memset(buf,0,sizeof(buf)); 185 186 if (inet_pton(af, srcip, buf)!=1) 187 break; 188 189 if (af==AF_INET) { 190 struct sockaddr_in *src4=(struct sockaddr_in*)src; 191 if (!src_f) { 192 if (src4->sin_addr.s_addr != buf[0]) 193 break; 194 src_f = 1; 195 } 196 } 197 } 198 if (strncmp(token, SRC_PORT, sizeof(SRC_PORT) - 1) == 0) { 199 char *src_port = token + sizeof(SRC_PORT) - 1; 200 uint16_t port=atoi(src_port); 201 202 if (af==AF_INET) { 203 struct sockaddr_in *src4=(struct sockaddr_in*)src; 204 if (!src_port_f) { 205 if (ntohs(src4->sin_port) != port) 206 break; 207 src_port_f = 1; 208 } 209 } 210 } 211 212 if (strncmp(token, DST, sizeof(DST) - 1) == 0) { 213 char *dstip = token + sizeof(DST) - 1; 214 uint32_t buf[4]; 215 memset(buf,0,sizeof(buf)); 216 if (inet_pton(af, dstip, buf)!=1) 217 break; 218 if (af==AF_INET) { 219 struct sockaddr_in *dst4=(struct sockaddr_in*)dst; 220 if (!dst_f) { 221 if (dst4->sin_addr.s_addr != buf[0]) 222 break; 223 dst_f = 1; 224 } else { 225 struct sockaddr_in*ret4=(struct sockaddr_in*)ret_ext; 226 ret_ext->ss_family = AF_INET; 227 ret4->sin_addr.s_addr = buf[0]; 228 } 229 } 230 } 231 if (strncmp(token, DST_PORT, sizeof(DST_PORT)-1) == 0) { 232 char *dst_port = token + sizeof(DST_PORT) - 1; 233 uint16_t port=atoi(dst_port); 234 if (af==AF_INET) { 235 struct sockaddr_in *dst4=(struct sockaddr_in*)dst; 236 if (!dst_port_f) { 237 if (ntohs(dst4->sin_port) != port) 238 break; 239 dst_port_f = 1; 240 } else { 241 struct sockaddr_in*ret4=(struct sockaddr_in*)ret_ext; 242 ret_ext->ss_family = AF_INET; 243 ret4->sin_port = htons(port); 244 } 245 } 246 } 247 } 248 if (src_f && src_port_f && dst_f && dst_port_f) { 249 fclose(f); 250 return 1; 251 } 252 } 253 } 254 fclose(f); 255 256 return 0; 257} 258#endif 259