1/* 2 * MiniUPnP project 3 * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ 4 * (c) 2015 Tomofumi Hayashi 5 * 6 * This software is subject to the conditions detailed 7 * in the LICENCE file provided within the distribution. 8 */ 9#include <stdio.h> 10#include <stddef.h> 11#include <stdlib.h> 12#include <string.h> 13#include <syslog.h> 14#include <sys/errno.h> 15#include <sys/socket.h> 16#include <sys/types.h> 17#include <netinet/in.h> 18#include <netinet/ip.h> 19#include <netinet/tcp.h> 20#include <arpa/inet.h> 21#include <dlfcn.h> 22 23#include <linux/version.h> 24 25#include <linux/netfilter.h> 26#include <linux/netfilter/nfnetlink.h> 27#include <linux/netfilter/nf_tables.h> 28 29#include <libmnl/libmnl.h> 30#include <libnftnl/rule.h> 31#include <libnftnl/expr.h> 32 33#include "tiny_nf_nat.h" 34 35#include "../macros.h" 36#include "../config.h" 37#include "nftnlrdr.h" 38#include "../upnpglobalvars.h" 39 40#include "nftnlrdr_misc.h" 41 42#ifdef DEBUG 43#define d_printf(x) do { printf x; } while (0) 44#else 45#define d_printf(x) 46#endif 47 48/* dummy init and shutdown functions */ 49int init_redirect(void) 50{ 51 return 0; 52} 53 54void shutdown_redirect(void) 55{ 56 return; 57} 58 59 60int 61add_redirect_rule2(const char * ifname, 62 const char * rhost, unsigned short eport, 63 const char * iaddr, unsigned short iport, int proto, 64 const char * desc, unsigned int timestamp) 65{ 66 struct nft_rule *r; 67 UNUSED(rhost); 68 UNUSED(timestamp); 69 d_printf(("add redirect rule2(%s, %s, %u, %s, %u, %d, %s)!\n", 70 ifname, rhost, eport, iaddr, iport, proto, desc)); 71 r = rule_set_dnat(NFPROTO_IPV4, ifname, proto, 72 0, eport, 73 inet_addr(iaddr), iport, desc, NULL); 74 return nft_send_request(r, NFT_MSG_NEWRULE); 75} 76 77/* 78 * This function submit the rule as following: 79 * nft add rule nat miniupnpd-pcp-peer ip 80 * saddr <iaddr> ip daddr <rhost> tcp sport <iport> 81 * tcp dport <rport> snat <eaddr>:<eport> 82 */ 83int 84add_peer_redirect_rule2(const char * ifname, 85 const char * rhost, unsigned short rport, 86 const char * eaddr, unsigned short eport, 87 const char * iaddr, unsigned short iport, int proto, 88 const char * desc, unsigned int timestamp) 89{ 90 struct nft_rule *r; 91 UNUSED(ifname); UNUSED(timestamp); 92 93 d_printf(("add peer redirect rule2()!\n")); 94 r = rule_set_snat(NFPROTO_IPV4, proto, 95 inet_addr(rhost), rport, 96 inet_addr(eaddr), eport, 97 inet_addr(iaddr), iport, desc, NULL); 98 99 return nft_send_request(r, NFT_MSG_NEWRULE); 100} 101 102/* 103 * This function submit the rule as following: 104 * nft add rule filter miniupnpd 105 * ip daddr <iaddr> tcp dport <iport> accept 106 * 107 */ 108int 109add_filter_rule2(const char * ifname, 110 const char * rhost, const char * iaddr, 111 unsigned short eport, unsigned short iport, 112 int proto, const char * desc) 113{ 114 struct nft_rule *r = NULL; 115 in_addr_t rhost_addr = 0; 116 117 d_printf(("add_filter_rule2(%s, %s, %s, %d, %d, %d, %s)\n", 118 ifname, rhost, iaddr, eport, iport, proto, desc)); 119 if (rhost != NULL && strcmp(rhost, "") != 0) { 120 rhost_addr = inet_addr(rhost); 121 } 122 r = rule_set_filter(NFPROTO_IPV4, ifname, proto, 123 rhost_addr, inet_addr(iaddr), eport, iport, 124 desc, 0); 125 return nft_send_request(r, NFT_MSG_NEWRULE); 126} 127 128/* 129 * add_peer_dscp_rule2() is not supported due to nft does not support 130 * dscp set. 131 */ 132int 133add_peer_dscp_rule2(const char * ifname, 134 const char * rhost, unsigned short rport, 135 unsigned char dscp, 136 const char * iaddr, unsigned short iport, int proto, 137 const char * desc, unsigned int timestamp) 138{ 139 UNUSED(ifname); UNUSED(rhost); UNUSED(rport); 140 UNUSED(dscp); UNUSED(iaddr); UNUSED(iport); UNUSED(proto); 141 UNUSED(desc); UNUSED(timestamp); 142 syslog(LOG_ERR, "add_peer_dscp_rule2: not supported"); 143 return 0; 144} 145 146/* 147 * Clear all rules corresponding eport/proto 148 */ 149int 150delete_redirect_and_filter_rules(unsigned short eport, int proto) 151{ 152 rule_t *p; 153 struct nft_rule *r = NULL; 154 in_addr_t iaddr = 0; 155 uint16_t iport = 0; 156 extern void print_rule(rule_t *r) ; 157 158 d_printf(("delete_redirect_and_filter_rules(%d %d)\n", eport, proto)); 159 reflesh_nft_cache(NFPROTO_IPV4); 160 LIST_FOREACH(p, &head, entry) { 161 if (p->eport == eport && p->proto == proto && 162 (p->type == RULE_NAT || p->type == RULE_SNAT)) { 163 iaddr = p->iaddr; 164 iport = p->iport; 165 166 r = rule_del_handle(p); 167 /* Todo: send bulk request */ 168 nft_send_request(r, NFT_MSG_DELRULE); 169 break; 170 } 171 } 172 173 if (iaddr == 0 && iport == 0) { 174 return -1; 175 } 176 reflesh_nft_cache(NFPROTO_IPV4); 177 LIST_FOREACH(p, &head, entry) { 178 if (p->eport == iport && 179 p->iaddr == iaddr && p->type == RULE_FILTER) { 180 r = rule_del_handle(p); 181 /* Todo: send bulk request */ 182 nft_send_request(r, NFT_MSG_DELRULE); 183 break; 184 } 185 } 186 187 return 0; 188} 189 190/* 191 * get peer by index as array. 192 * return -1 when not found. 193 */ 194int 195get_peer_rule_by_index(int index, 196 char * ifname, unsigned short * eport, 197 char * iaddr, int iaddrlen, unsigned short * iport, 198 int * proto, char * desc, int desclen, 199 char * rhost, int rhostlen, unsigned short * rport, 200 unsigned int * timestamp, 201 u_int64_t * packets, u_int64_t * bytes) 202{ 203 int i; 204 struct in_addr addr; 205 char *addr_str; 206 rule_t *r; 207 UNUSED(timestamp); UNUSED(packets); UNUSED(bytes); 208 209 d_printf(("get_peer_rule_by_index()\n")); 210 reflesh_nft_cache(NFPROTO_IPV4); 211 if (peer_cache == NULL) { 212 return -1; 213 } 214 215 for (i = 0; peer_cache[i] != NULL; i++) { 216 if (index == i) { 217 r = peer_cache[i]; 218 if (ifname != NULL) { 219 if_indextoname(r->ingress_ifidx, ifname); 220 } 221 if (eport != NULL) { 222 *eport = r->eport; 223 } 224 if (iaddr != NULL) { 225 addr.s_addr = r->iaddr; 226 addr_str = inet_ntoa(addr); 227 strncpy(iaddr , addr_str, iaddrlen); 228 } 229 if (iport != NULL) { 230 *iport = r->iport; 231 } 232 if (proto != NULL) { 233 *proto = r->proto; 234 } 235 if (rhost != NULL) { 236 addr.s_addr = r->rhost; 237 addr_str = inet_ntoa(addr); 238 strncpy(iaddr , addr_str, rhostlen); 239 } 240 if (rport != NULL) { 241 *rport = r->rport; 242 } 243 if (desc != NULL) { 244 strncpy(desc, r->desc, desclen); 245 } 246 247 /* 248 * TODO: Implement counter in case of add {nat,filter} 249 */ 250 return 0; 251 } 252 } 253 return -1; 254} 255 256/* 257 * get_redirect_rule() 258 * returns -1 if the rule is not found 259 */ 260int 261get_redirect_rule(const char * ifname, unsigned short eport, int proto, 262 char * iaddr, int iaddrlen, unsigned short * iport, 263 char * desc, int desclen, 264 char * rhost, int rhostlen, 265 unsigned int * timestamp, 266 u_int64_t * packets, u_int64_t * bytes) 267{ 268 return get_nat_redirect_rule(NFT_TABLE_NAT, 269 ifname, eport, proto, 270 iaddr, iaddrlen, iport, 271 desc, desclen, 272 rhost, rhostlen, 273 timestamp, packets, bytes); 274} 275 276/* 277 * get_redirect_rule_by_index() 278 * return -1 when the rule was not found 279 */ 280int 281get_redirect_rule_by_index(int index, 282 char * ifname, unsigned short * eport, 283 char * iaddr, int iaddrlen, unsigned short * iport, 284 int * proto, char * desc, int desclen, 285 char * rhost, int rhostlen, 286 unsigned int * timestamp, 287 u_int64_t * packets, u_int64_t * bytes) 288{ 289 int i; 290 struct in_addr addr; 291 char *addr_str; 292 rule_t *r; 293 UNUSED(timestamp); UNUSED(packets); UNUSED(bytes); 294 295 d_printf(("get_redirect_rule_by_index()\n")); 296 reflesh_nft_cache(NFPROTO_IPV4); 297 if (redirect_cache == NULL) { 298 return -1; 299 } 300 301 for (i = 0; redirect_cache[i] != NULL; i++) { 302 if (index == i) { 303 r = redirect_cache[i]; 304 if (ifname != NULL) { 305 if_indextoname(r->ingress_ifidx, ifname); 306 } 307 if (eport != NULL) { 308 *eport = r->eport; 309 } 310 if (iaddr != NULL) { 311 addr.s_addr = r->iaddr; 312 addr_str = inet_ntoa(addr); 313 strncpy(iaddr , addr_str, iaddrlen); 314 } 315 if (iport != NULL) { 316 *iport = r->iport; 317 } 318 if (proto != NULL) { 319 *proto = r->proto; 320 } 321 if (rhost != NULL) { 322 addr.s_addr = r->rhost; 323 addr_str = inet_ntoa(addr); 324 strncpy(iaddr , addr_str, rhostlen); 325 } 326 if (desc != NULL && r->desc) { 327 strncpy(desc, r->desc, desclen); 328 } 329 330 /* 331 * TODO: Implement counter in case of add {nat,filter} 332 */ 333 return 0; 334 } 335 } 336 return -1; 337} 338 339/* 340 * return -1 not found. 341 * return 0 found 342 */ 343int 344get_nat_redirect_rule(const char * nat_chain_name, const char * ifname, 345 unsigned short eport, int proto, 346 char * iaddr, int iaddrlen, unsigned short * iport, 347 char * desc, int desclen, 348 char * rhost, int rhostlen, 349 unsigned int * timestamp, 350 u_int64_t * packets, u_int64_t * bytes) 351{ 352 rule_t *p; 353 struct in_addr addr; 354 char *addr_str; 355 UNUSED(nat_chain_name); 356 UNUSED(ifname); 357 UNUSED(iaddrlen); 358 UNUSED(timestamp); 359 UNUSED(packets); 360 UNUSED(bytes); 361 362 d_printf(("get_nat_redirect_rule()\n")); 363 reflesh_nft_cache(NFPROTO_IPV4); 364 365 LIST_FOREACH(p, &head, entry) { 366 if (p->proto == proto && 367 p->eport == eport) { 368 if (p->rhost && rhost) { 369 addr.s_addr = p->rhost; 370 addr_str = inet_ntoa(addr); 371 strncpy(iaddr , addr_str, rhostlen); 372 373 } 374 if (desc != NULL && p->desc) { 375 strncpy(desc, p->desc, desclen); 376 } 377 *iport = p->iport; 378 return 0; 379 } 380 } 381 382 return -1; 383} 384 385/* 386 * return an (malloc'ed) array of "external" port for which there is 387 * a port mapping. number is the size of the array 388 */ 389unsigned short * 390get_portmappings_in_range(unsigned short startport, unsigned short endport, 391 int proto, unsigned int * number) 392{ 393 uint32_t capacity; 394 rule_t *p; 395 unsigned short *array; 396 unsigned short *tmp; 397 398 d_printf(("get_portmappings_in_range()\n")); 399 *number = 0; 400 capacity = 128; 401 array = calloc(capacity, sizeof(unsigned short)); 402 403 if (array == NULL) { 404 syslog(LOG_ERR, "get_portmappings_in_range(): calloc error"); 405 return NULL; 406 } 407 408 LIST_FOREACH(p, &head, entry) { 409 if (p->proto == proto && 410 startport <= p->eport && 411 p->eport <= endport) { 412 413 if (*number >= capacity) { 414 tmp = realloc(array, 415 sizeof(unsigned short)*capacity); 416 if (tmp == NULL) { 417 syslog(LOG_ERR, 418 "get_portmappings_in_range(): " 419 "realloc(%u) error", 420 (unsigned)sizeof(unsigned short)*capacity); 421 *number = 0; 422 free(array); 423 return NULL; 424 } 425 array = tmp; 426 } 427 array[*number] = p->eport; 428 (*number)++; 429 } 430 } 431 return array; 432} 433 434/* for debug */ 435/* read the "filter" and "nat" tables */ 436int 437list_redirect_rule(const char * ifname) 438{ 439 rule_t *p; 440 UNUSED(ifname); 441 442 reflesh_nft_cache(NFPROTO_IPV4); 443 444 LIST_FOREACH(p, &head, entry) { 445 print_rule(p); 446 } 447 448 return -1; 449 return 0; 450} 451 452 453#if 0 454/* delete_rule_and_commit() : 455 * subfunction used in delete_redirect_and_filter_rules() */ 456static int 457delete_rule_and_commit(unsigned int index, IPTC_HANDLE h, 458 const char * miniupnpd_chain, 459 const char * logcaller) 460{ 461/* TODO: Implement it */ 462} 463 464/* TODO: Implement it */ 465static void 466print_iface(const char * iface, const unsigned char * mask, int invert) 467{ 468 unsigned i; 469 if(mask[0] == 0) 470 return; 471 if(invert) 472 printf("! "); 473 for(i=0; i<IFNAMSIZ; i++) 474 { 475 if(mask[i]) 476 { 477 if(iface[i]) 478 putchar(iface[i]); 479 } 480 else 481 { 482 if(iface[i-1]) 483 putchar('+'); 484 break; 485 } 486 } 487 return ; 488} 489 490#ifdef DEBUG 491static void 492printip(uint32_t ip) 493{ 494 printf("%u.%u.%u.%u", ip >> 24, (ip >> 16) & 0xff, 495 (ip >> 8) & 0xff, ip & 0xff); 496} 497#endif 498 499#endif /* if 0 */ 500