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