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