1dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat/*
2dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * m_nat.c		NAT module
3dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
4dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		This program is free software; you can distribute it and/or
5dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		modify it under the terms of the GNU General Public License
6dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		as published by the Free Software Foundation; either version
7dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *		2 of the License, or (at your option) any later version.
8dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
9dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat * Authors:	Herbert Xu <herbert@gondor.apana.org.au>
10dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat *
11dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat */
12dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
13dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdio.h>
14dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <stdlib.h>
15dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <unistd.h>
16dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <syslog.h>
17dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <fcntl.h>
18dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <sys/socket.h>
19dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <netinet/in.h>
20dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <arpa/inet.h>
21dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <string.h>
22dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "utils.h"
23dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include "tc_util.h"
24dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat#include <linux/tc_act/tc_nat.h>
25dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
26dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void
27dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatexplain(void)
28dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
29dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(stderr, "Usage: ... nat NAT\n"
30dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			"NAT := DIRECTION OLD NEW\n"
31dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			"DIRECTION := { ingress | egress }\n"
32dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			"OLD := PREFIX\n"
33dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			"NEW := ADDRESS\n");
34dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
35dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
36dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic void
37dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatusage(void)
38dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
39dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	explain();
40dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	exit(-1);
41dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
42dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
43dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int
44dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatparse_nat_args(int *argc_p, char ***argv_p,struct tc_nat *sel)
45dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
46dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int argc = *argc_p;
47dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char **argv = *argv_p;
48dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	inet_prefix addr;
49dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
50dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (argc <= 0)
51dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
52dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
53dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (matches(*argv, "egress") == 0)
54dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		sel->flags |= TCA_NAT_FLAG_EGRESS;
55dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	else if (matches(*argv, "ingress") != 0)
56dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		goto bad_val;
57dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
58dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	NEXT_ARG();
59dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
60dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (get_prefix_1(&addr, *argv, AF_INET))
61dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		goto bad_val;
62dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
63dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	sel->old_addr = addr.data[0];
64dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	sel->mask = htonl(~0u << (32 - addr.bitlen));
65dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
66dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	NEXT_ARG();
67dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
68dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (get_prefix_1(&addr, *argv, AF_INET))
69dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		goto bad_val;
70dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
71dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	sel->new_addr = addr.data[0];
72dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
73dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	argc--;
74dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	argv++;
75dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
76dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*argc_p = argc;
77dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*argv_p = argv;
78dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
79dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
80dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatbad_val:
81dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return -1;
82dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
83dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
84dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int
85dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatparse_nat(struct action_util *a, int *argc_p, char ***argv_p, int tca_id, struct nlmsghdr *n)
86dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
87dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_nat sel;
88dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
89dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int argc = *argc_p;
90dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char **argv = *argv_p;
91dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int ok = 0;
92dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *tail;
93dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
94dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	memset(&sel, 0, sizeof(sel));
95dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
96dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	while (argc > 0) {
97dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (matches(*argv, "nat") == 0) {
98dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
99dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (parse_nat_args(&argc, &argv, &sel)) {
100dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Illegal nat construct (%s) \n",
101dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					*argv);
102dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				explain();
103dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
104dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
105dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			ok++;
106dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			continue;
107dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "help") == 0) {
108dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			usage();
109dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else {
110dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			break;
111dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
112dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
113dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
114dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
115dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (!ok) {
116dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		explain();
117dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
118dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
119dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
120dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (argc) {
121dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (matches(*argv, "reclassify") == 0) {
122dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			sel.action = TC_ACT_RECLASSIFY;
123dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argc--;
124dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argv++;
125dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "pipe") == 0) {
126dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			sel.action = TC_ACT_PIPE;
127dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argc--;
128dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argv++;
129dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "drop") == 0 ||
130dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			matches(*argv, "shot") == 0) {
131dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			sel.action = TC_ACT_SHOT;
132dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argc--;
133dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argv++;
134dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "continue") == 0) {
135dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			sel.action = TC_ACT_UNSPEC;
136dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argc--;
137dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argv++;
138dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		} else if (matches(*argv, "pass") == 0) {
139dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			sel.action = TC_ACT_OK;
140dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argc--;
141dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argv++;
142dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
143dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
144dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
145dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (argc) {
146dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (matches(*argv, "index") == 0) {
147dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			NEXT_ARG();
148dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			if (get_u32(&sel.index, *argv, 10)) {
149dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				fprintf(stderr, "Pedit: Illegal \"index\"\n");
150dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat				return -1;
151dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			}
152dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argc--;
153dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			argv++;
154dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
155dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
156dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
157dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	tail = NLMSG_TAIL(n);
158dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, MAX_MSG, tca_id, NULL, 0);
159dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	addattr_l(n, MAX_MSG, TCA_NAT_PARMS, &sel, sizeof(sel));
160dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	tail->rta_len = (char *)NLMSG_TAIL(n) - (char *)tail;
161dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
162dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*argc_p = argc;
163dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	*argv_p = argv;
164dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
165dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
166dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
167dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstatic int
168dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatprint_nat(struct action_util *au,FILE * f, struct rtattr *arg)
169dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat{
170dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct tc_nat *sel;
171dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	struct rtattr *tb[TCA_NAT_MAX + 1];
172dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char buf1[256];
173dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	char buf2[256];
174dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	SPRINT_BUF(buf3);
175dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	int len;
176dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
177dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (arg == NULL)
178dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
179dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
180dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	parse_rtattr_nested(tb, TCA_NAT_MAX, arg);
181dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
182dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (tb[TCA_NAT_PARMS] == NULL) {
183dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		fprintf(f, "[NULL nat parameters]");
184dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		return -1;
185dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
186dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	sel = RTA_DATA(tb[TCA_NAT_PARMS]);
187dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
188dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	len = ffs(sel->mask);
189dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	len = len ? 33 - len : 0;
190dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
191dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	fprintf(f, " nat %s %s/%d %s %s", sel->flags & TCA_NAT_FLAG_EGRESS ?
192dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat					  "egress" : "ingress",
193dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		format_host(AF_INET, 4, &sel->old_addr, buf1, sizeof(buf1)),
194dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		len,
195dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		format_host(AF_INET, 4, &sel->new_addr, buf2, sizeof(buf2)),
196dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		action_n2a(sel->action, buf3, sizeof (buf3)));
197dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
198dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	if (show_stats) {
199dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		if (tb[TCA_NAT_TM]) {
200dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			struct tcf_t *tm = RTA_DATA(tb[TCA_NAT_TM]);
201dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat			print_tm(f,tm);
202dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat		}
203dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	}
204dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
205dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	return 0;
206dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat}
207dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat
208dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehatstruct action_util nat_action_util = {
209dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.id = "nat",
210dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.parse_aopt = parse_nat,
211dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat	.print_aopt = print_nat,
212dcfb7a77f8709125e97c313cb8ab6ec4d87468f4San Mehat};
213