• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/miniupnpd/netfilter_nft/
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