1 /* $Id: nftnlrdr.c,v 1.10 2020/11/11 12:08:43 nanard Exp $
2 * vim: tabstop=4 shiftwidth=4 noexpandtab
3 * MiniUPnP project
4 * http://miniupnp.free.fr/ or https://miniupnp.tuxfamily.org/
5 * (c) 2015 Tomofumi Hayashi
6 * (c) 2019 Sven Auhagen
7 * (c) 2019 Paul Chambers
8 * (c) 2020 Thomas Bernard
9 *
10 * This software is subject to the conditions detailed
11 * in the LICENCE file provided within the distribution.
12 */
13 #include <stdio.h>
14 #include <stddef.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <syslog.h>
18 #include <errno.h>
19 #include <sys/socket.h>
20 #include <sys/types.h>
21 #include <netinet/in.h>
22 #include <netinet/ip.h>
23 #include <netinet/tcp.h>
24 #include <arpa/inet.h>
25 #include <dlfcn.h>
26 #include <net/if.h>
27
28 #include <linux/version.h>
29
30 #include <linux/netfilter.h>
31 #include <linux/netfilter_ipv4.h>
32 #include <linux/netfilter/nfnetlink.h>
33 #include <linux/netfilter/nf_tables.h>
34
35 #include <libmnl/libmnl.h>
36 #include <libnftnl/table.h>
37 #include <libnftnl/chain.h>
38 #include <libnftnl/rule.h>
39 #include <libnftnl/expr.h>
40
41 #include "tiny_nf_nat.h"
42
43 #include "config.h"
44 #include "../macros.h"
45 #include "../commonrdr.h"
46 #include "nftnlrdr.h"
47
48 #include "nftnlrdr_misc.h"
49
50 #ifdef DEBUG
51 #define d_printf(x) do { printf x; } while (0)
52 #else
53 #define d_printf(x)
54 #endif
55
56 /* list to keep timestamps for port mappings having a lease duration */
57 struct timestamp_entry {
58 struct timestamp_entry * next;
59 unsigned int timestamp;
60 unsigned short eport;
61 short protocol;
62 };
63
64 static struct timestamp_entry * timestamp_list = NULL;
65
66 #define NAT_CHAIN_TYPE "nat"
67 #define FILTER_CHAIN_TYPE "filter"
68
69 /* init and shutdown functions */
70 int
init_redirect(void)71 init_redirect(void)
72 {
73 int result;
74
75 /* requires elevated privileges */
76 result = nft_mnl_connect();
77
78 /* 'inet' family */
79 if (result == 0) {
80 result = table_op(NFT_MSG_NEWTABLE, NFPROTO_INET, nft_table);
81 }
82 if (result == 0) {
83 result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_INET, nft_table,
84 nft_forward_chain, FILTER_CHAIN_TYPE, NF_INET_FORWARD, NF_IP_PRI_FILTER - 25);
85 }
86
87 /* 'ip' family */
88 if (result == 0) {
89 result = table_op(NFT_MSG_NEWTABLE, NFPROTO_IPV4, nft_table);
90 }
91 if (result == 0) {
92 result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV4, nft_table,
93 nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST);
94 }
95 if (result == 0) {
96 result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV4, nft_table,
97 nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC);
98 }
99
100 /* 'ip6' family */
101 if (result == 0) {
102 result = table_op(NFT_MSG_NEWTABLE, NFPROTO_IPV6, nft_table);
103 }
104 if (result == 0) {
105 result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV6, nft_table,
106 nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST);
107 }
108 if (result == 0) {
109 result = chain_op(NFT_MSG_NEWCHAIN, NFPROTO_IPV6, nft_table,
110 nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC);
111 }
112
113 return result;
114 }
115
116 void
shutdown_redirect(void)117 shutdown_redirect(void)
118 {
119 int result;
120
121 /* 'inet' family */
122 result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_INET, nft_table,
123 nft_forward_chain, FILTER_CHAIN_TYPE, NF_INET_FORWARD, NF_IP_PRI_FILTER - 25);
124 if (result == 0) {
125 result = table_op(NFT_MSG_DELTABLE, NFPROTO_INET, nft_table);
126 }
127
128 /* 'ip' family */
129 result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV4, nft_table,
130 nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST);
131 if (result == 0) {
132 result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV4, nft_table,
133 nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC);
134 }
135 if (result == 0) {
136 result = table_op(NFT_MSG_DELTABLE, NFPROTO_IPV4, nft_table);
137 }
138
139 /* 'ip6' family */
140 if (result == 0) {
141 result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV6, nft_table,
142 nft_prerouting_chain, NAT_CHAIN_TYPE, NF_INET_PRE_ROUTING, NF_IP_PRI_NAT_DST);
143 }
144 if (result == 0) {
145 result = chain_op(NFT_MSG_DELCHAIN, NFPROTO_IPV6, nft_table,
146 nft_postrouting_chain, NAT_CHAIN_TYPE, NF_INET_POST_ROUTING, NF_IP_PRI_NAT_SRC);
147 }
148 if (result == 0) {
149 result = table_op(NFT_MSG_DELTABLE, NFPROTO_IPV6, nft_table);
150 }
151
152 nft_mnl_disconnect();
153 }
154
155 /**
156 * used by the core to override default chain names if specified in config file
157 * @param param which string to set
158 * @param string the new name to use. Do not dispose after setting (i.e. use strdup if not static).
159 * @return 0 if successful
160 */
161 int
set_rdr_name(rdr_name_type param,const char * string)162 set_rdr_name(rdr_name_type param, const char *string)
163 {
164 if (string == NULL || strlen(string) > 30 || string[0] == '\0') {
165 syslog(LOG_ERR, "%s(): invalid string argument '%s'", "set_rdr_name", string);
166 return -1;
167 }
168 switch (param) {
169 case RDR_TABLE_NAME:
170 nft_table = string;
171 break;
172 case RDR_NAT_PREROUTING_CHAIN_NAME:
173 nft_prerouting_chain = string;
174 break;
175 case RDR_NAT_POSTROUTING_CHAIN_NAME:
176 nft_postrouting_chain = string;
177 break;
178 case RDR_FORWARD_CHAIN_NAME:
179 nft_forward_chain = string;
180 break;
181 default:
182 syslog(LOG_ERR, "%s(): tried to set invalid string parameter: %d", "set_rdr_name", param);
183 return -2;
184 }
185 return 0;
186 }
187
188 static unsigned int
get_timestamp(unsigned short eport,int proto)189 get_timestamp(unsigned short eport, int proto)
190 {
191 struct timestamp_entry * e;
192 e = timestamp_list;
193 while(e) {
194 if(e->eport == eport && e->protocol == (short)proto) {
195 syslog(LOG_DEBUG, "timestamp entry found (%hu, %d, %u)", eport, proto, e->timestamp);
196 return e->timestamp;
197 }
198 e = e->next;
199 }
200 syslog(LOG_WARNING, "get_timestamp(%hu, %d) no entry found", eport, proto);
201 return 0;
202 }
203
204 static void
remove_timestamp_entry(unsigned short eport,int proto)205 remove_timestamp_entry(unsigned short eport, int proto)
206 {
207 struct timestamp_entry * e;
208 struct timestamp_entry * * p;
209 p = ×tamp_list;
210 e = *p;
211 while(e) {
212 if(e->eport == eport && e->protocol == (short)proto) {
213 syslog(LOG_DEBUG, "timestamp entry removed (%hu, %d, %u)", eport, proto, e->timestamp);
214 /* remove the entry */
215 *p = e->next;
216 free(e);
217 return;
218 }
219 p = &(e->next);
220 e = *p;
221 }
222 syslog(LOG_WARNING, "remove_timestamp_entry(%hu, %d) no entry found", eport, proto);
223 }
224
225 static void
add_timestamp_entry(unsigned short eport,int proto,unsigned timestamp)226 add_timestamp_entry(unsigned short eport, int proto, unsigned timestamp)
227 {
228 struct timestamp_entry * tmp;
229 tmp = malloc(sizeof(struct timestamp_entry));
230 if(tmp)
231 {
232 tmp->next = timestamp_list;
233 tmp->timestamp = timestamp;
234 tmp->eport = eport;
235 tmp->protocol = (short)proto;
236 timestamp_list = tmp;
237 syslog(LOG_DEBUG, "timestamp entry added (%hu, %d, %u)", eport, proto, timestamp);
238 }
239 else
240 {
241 syslog(LOG_ERR, "add_timestamp_entry() malloc(%lu) error",
242 sizeof(struct timestamp_entry));
243 }
244 }
245
246 int
add_redirect_rule2(const char * ifname,const char * rhost,unsigned short eport,const char * iaddr,unsigned short iport,int proto,const char * desc,unsigned int timestamp)247 add_redirect_rule2(const char * ifname,
248 const char * rhost, unsigned short eport,
249 const char * iaddr, unsigned short iport, int proto,
250 const char * desc, unsigned int timestamp)
251 {
252 int ret;
253 struct nftnl_rule *r;
254 UNUSED(rhost);
255
256 d_printf(("add redirect rule2(%s, %s, %u, %s, %u, %d, %s)!\n",
257 ifname, rhost, eport, iaddr, iport, proto, desc));
258
259 r = rule_set_dnat(NFPROTO_IPV4, ifname, proto,
260 0, eport,
261 inet_addr(iaddr), iport, desc, NULL);
262
263 ret = nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_REDIRECT);
264 if (ret >= 0) {
265 add_timestamp_entry(eport, proto, timestamp);
266 }
267 return ret;
268 }
269
270 /*
271 * This function submit the rule as following:
272 * nft add rule nat miniupnpd-pcp-peer ip
273 * saddr <iaddr> ip daddr <rhost> tcp sport <iport>
274 * tcp dport <rport> snat <eaddr>:<eport>
275 */
276 int
add_peer_redirect_rule2(const char * ifname,const char * rhost,unsigned short rport,const char * eaddr,unsigned short eport,const char * iaddr,unsigned short iport,int proto,const char * desc,unsigned int timestamp)277 add_peer_redirect_rule2(const char * ifname,
278 const char * rhost, unsigned short rport,
279 const char * eaddr, unsigned short eport,
280 const char * iaddr, unsigned short iport, int proto,
281 const char * desc, unsigned int timestamp)
282 {
283 struct nftnl_rule *r;
284 UNUSED(ifname); UNUSED(timestamp);
285
286 d_printf(("add peer redirect rule2()!\n"));
287
288 r = rule_set_snat(NFPROTO_IPV4, proto,
289 inet_addr(rhost), rport,
290 inet_addr(eaddr), eport,
291 inet_addr(iaddr), iport, desc, NULL);
292
293 return nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_PEER);
294 }
295
296 /*
297 * This function submit the rule as following:
298 * nft add rule filter miniupnpd
299 * ip daddr <iaddr> tcp dport <iport> accept
300 *
301 */
302 int
add_filter_rule2(const char * ifname,const char * rhost,const char * iaddr,unsigned short eport,unsigned short iport,int proto,const char * desc)303 add_filter_rule2(const char * ifname,
304 const char * rhost, const char * iaddr,
305 unsigned short eport, unsigned short iport,
306 int proto, const char * desc)
307 {
308 struct nftnl_rule *r = NULL;
309 in_addr_t rhost_addr = 0;
310
311 d_printf(("add_filter_rule2(%s, %s, %s, %d, %d, %d, %s)\n",
312 ifname, rhost, iaddr, eport, iport, proto, desc));
313
314 if (rhost != NULL && strcmp(rhost, "") != 0 && strcmp(rhost, "*") != 0) {
315 rhost_addr = inet_addr(rhost);
316 }
317 r = rule_set_filter(NFPROTO_INET, ifname, proto,
318 rhost_addr, inet_addr(iaddr),
319 eport, iport, 0,
320 desc, 0);
321
322 return nft_send_rule(r, NFT_MSG_NEWRULE, RULE_CHAIN_FILTER);
323 }
324
325 /*
326 * add_peer_dscp_rule2() is not supported due to nft does not support
327 * dscp set.
328 */
329 int
add_peer_dscp_rule2(const char * ifname,const char * rhost,unsigned short rport,unsigned char dscp,const char * iaddr,unsigned short iport,int proto,const char * desc,unsigned int timestamp)330 add_peer_dscp_rule2(const char * ifname,
331 const char * rhost, unsigned short rport,
332 unsigned char dscp,
333 const char * iaddr, unsigned short iport, int proto,
334 const char * desc, unsigned int timestamp)
335 {
336 UNUSED(ifname); UNUSED(rhost); UNUSED(rport);
337 UNUSED(dscp); UNUSED(iaddr); UNUSED(iport); UNUSED(proto);
338 UNUSED(desc); UNUSED(timestamp);
339 syslog(LOG_ERR, "add_peer_dscp_rule2: not supported");
340 return 0;
341 }
342
343 int
delete_filter_rule(const char * ifname,unsigned short port,int proto)344 delete_filter_rule(const char * ifname, unsigned short port, int proto)
345 {
346 rule_t *p;
347 struct nftnl_rule *r;
348 UNUSED(ifname);
349
350 refresh_nft_cache_filter();
351 LIST_FOREACH(p, &head_filter, entry) {
352 if (p->eport == port && p->proto == proto && p->type == RULE_FILTER) {
353 r = rule_del_handle(p);
354 nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
355 break;
356 }
357 }
358
359 return 0;
360 }
361
362 /*
363 * Clear all rules corresponding eport/proto
364 */
365 int
delete_redirect_and_filter_rules(unsigned short eport,int proto)366 delete_redirect_and_filter_rules(unsigned short eport, int proto)
367 {
368 rule_t *p;
369 struct nftnl_rule *r = NULL;
370 in_addr_t iaddr = 0;
371 uint16_t iport = 0;
372
373 d_printf(("delete_redirect_and_filter_rules(%d %d)\n", eport, proto));
374 refresh_nft_cache_redirect();
375
376 // Delete Redirect Rule
377 LIST_FOREACH(p, &head_redirect, entry) {
378 if (p->eport == eport && p->proto == proto &&
379 (p->type == RULE_NAT && p->nat_type == NFT_NAT_DNAT)) {
380 iaddr = p->iaddr;
381 iport = p->iport;
382
383 r = rule_del_handle(p);
384 /* Todo: send bulk request */
385 nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_REDIRECT);
386 break;
387 }
388 }
389
390 if (iaddr != 0 && iport != 0) {
391 refresh_nft_cache_filter();
392 // Delete Forward Rule
393 LIST_FOREACH(p, &head_filter, entry) {
394 if (p->eport == iport &&
395 p->iaddr == iaddr && p->type == RULE_FILTER) {
396 r = rule_del_handle(p);
397 /* Todo: send bulk request */
398 nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
399 break;
400 }
401 }
402 }
403
404 iaddr = 0;
405 iport = 0;
406
407 refresh_nft_cache_peer();
408 // Delete Peer Rule
409 LIST_FOREACH(p, &head_peer, entry) {
410 if (p->eport == eport && p->proto == proto &&
411 (p->type == RULE_NAT && p->nat_type == NFT_NAT_SNAT)) {
412 iaddr = p->iaddr;
413 iport = p->iport;
414
415 r = rule_del_handle(p);
416 /* Todo: send bulk request */
417 nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_PEER);
418 break;
419 }
420 }
421
422 if (iaddr != 0 && iport != 0) {
423 refresh_nft_cache_filter();
424 // Delete Forward Rule
425 LIST_FOREACH(p, &head_filter, entry) {
426 if (p->eport == iport &&
427 p->iaddr == iaddr && p->type == RULE_FILTER) {
428 r = rule_del_handle(p);
429 /* Todo: send bulk request */
430 nft_send_rule(r, NFT_MSG_DELRULE, RULE_CHAIN_FILTER);
431 break;
432 }
433 }
434 }
435
436 return 0;
437 }
438
439 /*
440 * get peer by index as array.
441 * return -1 when not found.
442 */
443 int
get_peer_rule_by_index(int index,char * ifname,unsigned short * eport,char * iaddr,int iaddrlen,unsigned short * iport,int * proto,char * desc,int desclen,char * rhost,int rhostlen,unsigned short * rport,unsigned int * timestamp,u_int64_t * packets,u_int64_t * bytes)444 get_peer_rule_by_index(int index,
445 char * ifname, unsigned short * eport,
446 char * iaddr, int iaddrlen, unsigned short * iport,
447 int * proto, char * desc, int desclen,
448 char * rhost, int rhostlen, unsigned short * rport,
449 unsigned int * timestamp,
450 u_int64_t * packets, u_int64_t * bytes)
451 {
452 rule_t *r;
453 int i = 0;
454
455 d_printf(("get_peer_rule_by_index()\n"));
456 refresh_nft_cache_peer();
457
458 LIST_FOREACH(r, &head_peer, entry) {
459 if (i++ == index) {
460 if (ifname != NULL) {
461 if_indextoname(r->ingress_ifidx, ifname);
462 }
463
464 if (eport != NULL) {
465 *eport = r->eport;
466 }
467
468 if (iaddr != NULL) {
469 if (inet_ntop(AF_INET, &r->iaddr, iaddr, iaddrlen) == NULL) {
470 syslog(LOG_ERR, "%s: inet_ntop: %m",
471 "get_peer_rule_by_index");
472 }
473 }
474
475 if (iport != NULL) {
476 *iport = r->iport;
477 }
478
479 if (proto != NULL) {
480 *proto = r->proto;
481 }
482
483 if (rhost != NULL) {
484 if (r->rhost) {
485 if (inet_ntop(AF_INET, &r->rhost, rhost, rhostlen) == NULL) {
486 syslog(LOG_ERR, "%s: inet_ntop: %m",
487 "get_peer_rule_by_index");
488 }
489 } else {
490 rhost[0] = '\0';
491 }
492 }
493
494 if (rport != NULL) {
495 *rport = r->rport;
496 }
497
498 if (desc != NULL) {
499 strncpy(desc, r->desc, desclen);
500 }
501
502 if (packets) {
503 *packets = r->packets;
504 }
505 if (bytes) {
506 *bytes = r->bytes;
507 }
508
509 if (timestamp) {
510 *timestamp = get_timestamp(r->eport, r->proto);
511 }
512 /*
513 * TODO: Implement counter in case of add {nat,filter}
514 */
515 return 0;
516 }
517 }
518
519 return -1;
520 }
521
522 /*
523 * get_redirect_rule()
524 * returns -1 if the rule is not found
525 */
526 int
get_redirect_rule(const char * ifname,unsigned short eport,int proto,char * iaddr,int iaddrlen,unsigned short * iport,char * desc,int desclen,char * rhost,int rhostlen,unsigned int * timestamp,u_int64_t * packets,u_int64_t * bytes)527 get_redirect_rule(const char * ifname, unsigned short eport, int proto,
528 char * iaddr, int iaddrlen, unsigned short * iport,
529 char * desc, int desclen,
530 char * rhost, int rhostlen,
531 unsigned int * timestamp,
532 u_int64_t * packets, u_int64_t * bytes)
533 {
534 return get_nat_redirect_rule(nft_prerouting_chain,
535 ifname, eport, proto,
536 iaddr, iaddrlen, iport,
537 desc, desclen,
538 rhost, rhostlen,
539 timestamp, packets, bytes);
540 }
541
542 /* get_redirect_rule_count()
543 * return value : -1 for error or the number of redirection rules */
544 int
get_redirect_rule_count(const char * ifname)545 get_redirect_rule_count(const char * ifname)
546 {
547 rule_t *r;
548 int n = 0;
549 UNUSED(ifname);
550
551 refresh_nft_cache_redirect();
552 LIST_FOREACH(r, &head_redirect, entry) {
553 n++;
554 }
555 return n;
556 }
557
558 /*
559 * get_redirect_rule_by_index()
560 * return -1 when the rule was not found
561 */
562 int
get_redirect_rule_by_index(int index,char * ifname,unsigned short * eport,char * iaddr,int iaddrlen,unsigned short * iport,int * proto,char * desc,int desclen,char * rhost,int rhostlen,unsigned int * timestamp,u_int64_t * packets,u_int64_t * bytes)563 get_redirect_rule_by_index(int index,
564 char * ifname, unsigned short * eport,
565 char * iaddr, int iaddrlen, unsigned short * iport,
566 int * proto, char * desc, int desclen,
567 char * rhost, int rhostlen,
568 unsigned int * timestamp,
569 u_int64_t * packets, u_int64_t * bytes)
570 {
571 rule_t *r;
572 int i = 0;
573
574 d_printf(("get_redirect_rule_by_index()\n"));
575 refresh_nft_cache_redirect();
576
577 LIST_FOREACH(r, &head_redirect, entry) {
578 if (i++ == index) {
579 if (ifname != NULL) {
580 if_indextoname(r->ingress_ifidx, ifname);
581 }
582
583 if (eport != NULL) {
584 *eport = r->eport;
585 }
586
587 if (iaddr != NULL) {
588 if (inet_ntop(AF_INET, &r->iaddr, iaddr, iaddrlen) == NULL) {
589 syslog(LOG_ERR, "%s: inet_ntop: %m",
590 "get_redirect_rule_by_index");
591 }
592 }
593
594 if (iport != NULL) {
595 *iport = r->iport;
596 }
597
598 if (proto != NULL) {
599 *proto = r->proto;
600 }
601
602 if (rhost != NULL) {
603 if (r->rhost) {
604 if (inet_ntop(AF_INET, &r->rhost, rhost, rhostlen) == NULL) {
605 syslog(LOG_ERR, "%s: inet_ntop: %m",
606 "get_redirect_rule_by_index");
607 }
608 } else {
609 rhost[0] = '\0';
610 }
611 }
612
613 if (desc != NULL && r->desc) {
614 strncpy(desc, r->desc, desclen);
615 }
616
617 if (timestamp != NULL) {
618 *timestamp = get_timestamp(*eport, *proto);
619 }
620
621 if (packets || bytes) {
622 if (packets)
623 *packets = r->packets;
624 if (bytes)
625 *bytes = r->bytes;
626 }
627
628 /*
629 * TODO: Implement counter in case of add {nat,filter}
630 */
631 return 0;
632 }
633 }
634
635 return -1;
636 }
637
638 /*
639 * return -1 not found.
640 * return 0 found
641 */
642 int
get_nat_redirect_rule(const char * nat_chain_name,const char * ifname,unsigned short eport,int proto,char * iaddr,int iaddrlen,unsigned short * iport,char * desc,int desclen,char * rhost,int rhostlen,unsigned int * timestamp,u_int64_t * packets,u_int64_t * bytes)643 get_nat_redirect_rule(const char * nat_chain_name, const char * ifname,
644 unsigned short eport, int proto,
645 char * iaddr, int iaddrlen, unsigned short * iport,
646 char * desc, int desclen,
647 char * rhost, int rhostlen,
648 unsigned int * timestamp,
649 u_int64_t * packets, u_int64_t * bytes)
650 {
651 rule_t *p;
652 struct in_addr addr;
653 UNUSED(nat_chain_name);
654 UNUSED(ifname);
655 UNUSED(packets);
656 UNUSED(bytes);
657 UNUSED(rhost);
658 UNUSED(rhostlen);
659
660 refresh_nft_cache_redirect();
661
662 LIST_FOREACH(p, &head_redirect, entry) {
663 if (p->proto == proto &&
664 p->eport == eport) {
665
666 if (p->iaddr && iaddr) {
667 addr.s_addr = p->iaddr;
668 if (inet_ntop(AF_INET, &addr, iaddr, iaddrlen) == NULL) {
669 syslog(LOG_ERR, "%s: inet_ntop: %m",
670 "get_nat_redirect_rule");
671 }
672 }
673
674 if (desc != NULL && p->desc) {
675 strncpy(desc, p->desc, desclen);
676 }
677
678 if (iport)
679 *iport = p->iport;
680
681 if(timestamp != NULL)
682 *timestamp = get_timestamp(eport, proto);
683
684 return 0;
685 }
686 }
687
688 return -1;
689 }
690
691 /*
692 * return an (malloc'ed) array of "external" port for which there is
693 * a port mapping. number is the size of the array
694 */
695 unsigned short *
get_portmappings_in_range(unsigned short startport,unsigned short endport,int proto,unsigned int * number)696 get_portmappings_in_range(unsigned short startport, unsigned short endport,
697 int proto, unsigned int * number)
698 {
699 uint32_t capacity;
700 rule_t *p;
701 unsigned short *array;
702 unsigned short *tmp;
703
704 d_printf(("get_portmappings_in_range()\n"));
705
706 *number = 0;
707 capacity = 128;
708 array = calloc(capacity, sizeof(unsigned short));
709
710 if (array == NULL) {
711 syslog(LOG_ERR, "get_portmappings_in_range(): calloc error");
712 return NULL;
713 }
714
715 refresh_nft_cache_redirect();
716
717 LIST_FOREACH(p, &head_redirect, entry) {
718 if (p->proto == proto &&
719 startport <= p->eport &&
720 p->eport <= endport) {
721
722 if (*number >= capacity) {
723 tmp = realloc(array,
724 sizeof(unsigned short)*capacity);
725 if (tmp == NULL) {
726 syslog(LOG_ERR,
727 "get_portmappings_in_range(): "
728 "realloc(%u) error",
729 (unsigned)sizeof(unsigned short)*capacity);
730 *number = 0;
731 free(array);
732 return NULL;
733 }
734 array = tmp;
735 }
736 array[*number] = p->eport;
737 (*number)++;
738 }
739 }
740 return array;
741 }
742
743 int
update_portmapping_desc_timestamp(const char * ifname,unsigned short eport,int proto,const char * desc,unsigned int timestamp)744 update_portmapping_desc_timestamp(const char * ifname,
745 unsigned short eport, int proto,
746 const char * desc, unsigned int timestamp)
747 {
748 UNUSED(ifname);
749 UNUSED(desc);
750 remove_timestamp_entry(eport, proto);
751 add_timestamp_entry(eport, proto, timestamp);
752 return 0;
753 }
754
755 int
update_portmapping(const char * ifname,unsigned short eport,int proto,unsigned short iport,const char * desc,unsigned int timestamp)756 update_portmapping(const char * ifname, unsigned short eport, int proto,
757 unsigned short iport, const char * desc,
758 unsigned int timestamp)
759 {
760 char iaddr_str[INET_ADDRSTRLEN];
761 char rhost[INET_ADDRSTRLEN];
762 int r;
763
764 d_printf(("update_portmapping()\n"));
765
766 if (get_redirect_rule(NULL, eport, proto, iaddr_str, INET_ADDRSTRLEN, NULL, NULL, 0, rhost, INET_ADDRSTRLEN, NULL, 0, 0) < 0)
767 return -1;
768
769 r = delete_redirect_and_filter_rules(eport, proto);
770 if (r < 0)
771 return -1;
772
773 if (add_redirect_rule2(ifname, rhost, eport, iaddr_str, iport, proto,
774 desc, timestamp) < 0)
775 return -1;
776
777 if (add_filter_rule2(ifname, rhost, iaddr_str, eport, iport, proto, desc) < 0)
778 return -1;
779
780 return 0;
781 }
782