1*de1e4e89SAndroid Build Coastguard Worker /*
2*de1e4e89SAndroid Build Coastguard Worker * m_egress.c ingress/egress packet mirror/redir actions module
3*de1e4e89SAndroid Build Coastguard Worker *
4*de1e4e89SAndroid Build Coastguard Worker * This program is free software; you can distribute it and/or
5*de1e4e89SAndroid Build Coastguard Worker * modify it under the terms of the GNU General Public License
6*de1e4e89SAndroid Build Coastguard Worker * as published by the Free Software Foundation; either version
7*de1e4e89SAndroid Build Coastguard Worker * 2 of the License, or (at your option) any later version.
8*de1e4e89SAndroid Build Coastguard Worker *
9*de1e4e89SAndroid Build Coastguard Worker * Authors: J Hadi Salim ([email protected])
10*de1e4e89SAndroid Build Coastguard Worker *
11*de1e4e89SAndroid Build Coastguard Worker * TODO: Add Ingress support
12*de1e4e89SAndroid Build Coastguard Worker *
13*de1e4e89SAndroid Build Coastguard Worker */
14*de1e4e89SAndroid Build Coastguard Worker
15*de1e4e89SAndroid Build Coastguard Worker #include <stdio.h>
16*de1e4e89SAndroid Build Coastguard Worker #include <stdlib.h>
17*de1e4e89SAndroid Build Coastguard Worker #include <unistd.h>
18*de1e4e89SAndroid Build Coastguard Worker #include <syslog.h>
19*de1e4e89SAndroid Build Coastguard Worker #include <fcntl.h>
20*de1e4e89SAndroid Build Coastguard Worker #include <sys/socket.h>
21*de1e4e89SAndroid Build Coastguard Worker #include <netinet/in.h>
22*de1e4e89SAndroid Build Coastguard Worker #include <arpa/inet.h>
23*de1e4e89SAndroid Build Coastguard Worker #include <string.h>
24*de1e4e89SAndroid Build Coastguard Worker #include "utils.h"
25*de1e4e89SAndroid Build Coastguard Worker #include "tc_util.h"
26*de1e4e89SAndroid Build Coastguard Worker #include "tc_common.h"
27*de1e4e89SAndroid Build Coastguard Worker #include <linux/tc_act/tc_mirred.h>
28*de1e4e89SAndroid Build Coastguard Worker
29*de1e4e89SAndroid Build Coastguard Worker static void
explain(void)30*de1e4e89SAndroid Build Coastguard Worker explain(void)
31*de1e4e89SAndroid Build Coastguard Worker {
32*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Usage: mirred <DIRECTION> <ACTION> [index INDEX] <dev DEVICENAME>\n");
33*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "where:\n");
34*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\tDIRECTION := <ingress | egress>\n");
35*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\tACTION := <mirror | redirect>\n");
36*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\tINDEX is the specific policy instance id\n");
37*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "\tDEVICENAME is the devicename\n");
38*de1e4e89SAndroid Build Coastguard Worker
39*de1e4e89SAndroid Build Coastguard Worker }
40*de1e4e89SAndroid Build Coastguard Worker
41*de1e4e89SAndroid Build Coastguard Worker static void
usage(void)42*de1e4e89SAndroid Build Coastguard Worker usage(void)
43*de1e4e89SAndroid Build Coastguard Worker {
44*de1e4e89SAndroid Build Coastguard Worker explain();
45*de1e4e89SAndroid Build Coastguard Worker exit(-1);
46*de1e4e89SAndroid Build Coastguard Worker }
47*de1e4e89SAndroid Build Coastguard Worker
mirred_n2a(int action)48*de1e4e89SAndroid Build Coastguard Worker static const char *mirred_n2a(int action)
49*de1e4e89SAndroid Build Coastguard Worker {
50*de1e4e89SAndroid Build Coastguard Worker switch (action) {
51*de1e4e89SAndroid Build Coastguard Worker case TCA_EGRESS_REDIR:
52*de1e4e89SAndroid Build Coastguard Worker return "Egress Redirect";
53*de1e4e89SAndroid Build Coastguard Worker case TCA_INGRESS_REDIR:
54*de1e4e89SAndroid Build Coastguard Worker return "Ingress Redirect";
55*de1e4e89SAndroid Build Coastguard Worker case TCA_EGRESS_MIRROR:
56*de1e4e89SAndroid Build Coastguard Worker return "Egress Mirror";
57*de1e4e89SAndroid Build Coastguard Worker case TCA_INGRESS_MIRROR:
58*de1e4e89SAndroid Build Coastguard Worker return "Ingress Mirror";
59*de1e4e89SAndroid Build Coastguard Worker default:
60*de1e4e89SAndroid Build Coastguard Worker return "unknown";
61*de1e4e89SAndroid Build Coastguard Worker }
62*de1e4e89SAndroid Build Coastguard Worker }
63*de1e4e89SAndroid Build Coastguard Worker
64*de1e4e89SAndroid Build Coastguard Worker static int
parse_direction(struct action_util * a,int * argc_p,char *** argv_p,int tca_id,struct nlmsghdr * n)65*de1e4e89SAndroid Build Coastguard Worker parse_direction(struct action_util *a, int *argc_p, char ***argv_p,
66*de1e4e89SAndroid Build Coastguard Worker int tca_id, struct nlmsghdr *n)
67*de1e4e89SAndroid Build Coastguard Worker {
68*de1e4e89SAndroid Build Coastguard Worker
69*de1e4e89SAndroid Build Coastguard Worker int argc = *argc_p;
70*de1e4e89SAndroid Build Coastguard Worker char **argv = *argv_p;
71*de1e4e89SAndroid Build Coastguard Worker int ok = 0, iok = 0, mirror = 0, redir = 0, ingress = 0, egress = 0;
72*de1e4e89SAndroid Build Coastguard Worker struct tc_mirred p = {};
73*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tail;
74*de1e4e89SAndroid Build Coastguard Worker char d[16] = {};
75*de1e4e89SAndroid Build Coastguard Worker
76*de1e4e89SAndroid Build Coastguard Worker while (argc > 0) {
77*de1e4e89SAndroid Build Coastguard Worker
78*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "action") == 0) {
79*de1e4e89SAndroid Build Coastguard Worker break;
80*de1e4e89SAndroid Build Coastguard Worker } else if (!egress && matches(*argv, "egress") == 0) {
81*de1e4e89SAndroid Build Coastguard Worker egress = 1;
82*de1e4e89SAndroid Build Coastguard Worker if (ingress) {
83*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Can't have both egress and ingress\n");
84*de1e4e89SAndroid Build Coastguard Worker return -1;
85*de1e4e89SAndroid Build Coastguard Worker }
86*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
87*de1e4e89SAndroid Build Coastguard Worker ok++;
88*de1e4e89SAndroid Build Coastguard Worker continue;
89*de1e4e89SAndroid Build Coastguard Worker } else if (!ingress && matches(*argv, "ingress") == 0) {
90*de1e4e89SAndroid Build Coastguard Worker ingress = 1;
91*de1e4e89SAndroid Build Coastguard Worker if (egress) {
92*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Can't have both ingress and egress\n");
93*de1e4e89SAndroid Build Coastguard Worker return -1;
94*de1e4e89SAndroid Build Coastguard Worker }
95*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
96*de1e4e89SAndroid Build Coastguard Worker ok++;
97*de1e4e89SAndroid Build Coastguard Worker continue;
98*de1e4e89SAndroid Build Coastguard Worker } else {
99*de1e4e89SAndroid Build Coastguard Worker
100*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "index") == 0) {
101*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
102*de1e4e89SAndroid Build Coastguard Worker if (get_u32(&p.index, *argv, 10)) {
103*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Illegal \"index\"\n");
104*de1e4e89SAndroid Build Coastguard Worker return -1;
105*de1e4e89SAndroid Build Coastguard Worker }
106*de1e4e89SAndroid Build Coastguard Worker iok++;
107*de1e4e89SAndroid Build Coastguard Worker if (!ok) {
108*de1e4e89SAndroid Build Coastguard Worker argc--;
109*de1e4e89SAndroid Build Coastguard Worker argv++;
110*de1e4e89SAndroid Build Coastguard Worker break;
111*de1e4e89SAndroid Build Coastguard Worker }
112*de1e4e89SAndroid Build Coastguard Worker } else if (!ok) {
113*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "was expecting egress or ingress (%s)\n", *argv);
114*de1e4e89SAndroid Build Coastguard Worker break;
115*de1e4e89SAndroid Build Coastguard Worker
116*de1e4e89SAndroid Build Coastguard Worker } else if (!mirror && matches(*argv, "mirror") == 0) {
117*de1e4e89SAndroid Build Coastguard Worker mirror = 1;
118*de1e4e89SAndroid Build Coastguard Worker if (redir) {
119*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Can't have both mirror and redir\n");
120*de1e4e89SAndroid Build Coastguard Worker return -1;
121*de1e4e89SAndroid Build Coastguard Worker }
122*de1e4e89SAndroid Build Coastguard Worker p.eaction = egress ? TCA_EGRESS_MIRROR :
123*de1e4e89SAndroid Build Coastguard Worker TCA_INGRESS_MIRROR;
124*de1e4e89SAndroid Build Coastguard Worker p.action = TC_ACT_PIPE;
125*de1e4e89SAndroid Build Coastguard Worker ok++;
126*de1e4e89SAndroid Build Coastguard Worker } else if (!redir && matches(*argv, "redirect") == 0) {
127*de1e4e89SAndroid Build Coastguard Worker redir = 1;
128*de1e4e89SAndroid Build Coastguard Worker if (mirror) {
129*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Can't have both mirror and redir\n");
130*de1e4e89SAndroid Build Coastguard Worker return -1;
131*de1e4e89SAndroid Build Coastguard Worker }
132*de1e4e89SAndroid Build Coastguard Worker p.eaction = egress ? TCA_EGRESS_REDIR :
133*de1e4e89SAndroid Build Coastguard Worker TCA_INGRESS_REDIR;
134*de1e4e89SAndroid Build Coastguard Worker p.action = TC_ACT_STOLEN;
135*de1e4e89SAndroid Build Coastguard Worker ok++;
136*de1e4e89SAndroid Build Coastguard Worker } else if ((redir || mirror) && matches(*argv, "dev") == 0) {
137*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
138*de1e4e89SAndroid Build Coastguard Worker if (strlen(d))
139*de1e4e89SAndroid Build Coastguard Worker duparg("dev", *argv);
140*de1e4e89SAndroid Build Coastguard Worker
141*de1e4e89SAndroid Build Coastguard Worker strncpy(d, *argv, sizeof(d)-1);
142*de1e4e89SAndroid Build Coastguard Worker argc--;
143*de1e4e89SAndroid Build Coastguard Worker argv++;
144*de1e4e89SAndroid Build Coastguard Worker
145*de1e4e89SAndroid Build Coastguard Worker break;
146*de1e4e89SAndroid Build Coastguard Worker
147*de1e4e89SAndroid Build Coastguard Worker }
148*de1e4e89SAndroid Build Coastguard Worker }
149*de1e4e89SAndroid Build Coastguard Worker
150*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
151*de1e4e89SAndroid Build Coastguard Worker }
152*de1e4e89SAndroid Build Coastguard Worker
153*de1e4e89SAndroid Build Coastguard Worker if (!ok && !iok) {
154*de1e4e89SAndroid Build Coastguard Worker return -1;
155*de1e4e89SAndroid Build Coastguard Worker }
156*de1e4e89SAndroid Build Coastguard Worker
157*de1e4e89SAndroid Build Coastguard Worker
158*de1e4e89SAndroid Build Coastguard Worker
159*de1e4e89SAndroid Build Coastguard Worker if (d[0]) {
160*de1e4e89SAndroid Build Coastguard Worker int idx;
161*de1e4e89SAndroid Build Coastguard Worker
162*de1e4e89SAndroid Build Coastguard Worker ll_init_map(&rth);
163*de1e4e89SAndroid Build Coastguard Worker
164*de1e4e89SAndroid Build Coastguard Worker if ((idx = ll_name_to_index(d)) == 0) {
165*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot find device \"%s\"\n", d);
166*de1e4e89SAndroid Build Coastguard Worker return -1;
167*de1e4e89SAndroid Build Coastguard Worker }
168*de1e4e89SAndroid Build Coastguard Worker
169*de1e4e89SAndroid Build Coastguard Worker p.ifindex = idx;
170*de1e4e89SAndroid Build Coastguard Worker }
171*de1e4e89SAndroid Build Coastguard Worker
172*de1e4e89SAndroid Build Coastguard Worker
173*de1e4e89SAndroid Build Coastguard Worker if (p.eaction == TCA_EGRESS_MIRROR || p.eaction == TCA_INGRESS_MIRROR)
174*de1e4e89SAndroid Build Coastguard Worker parse_action_control(&argc, &argv, &p.action, false);
175*de1e4e89SAndroid Build Coastguard Worker
176*de1e4e89SAndroid Build Coastguard Worker if (argc) {
177*de1e4e89SAndroid Build Coastguard Worker if (iok && matches(*argv, "index") == 0) {
178*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "mirred: Illegal double index\n");
179*de1e4e89SAndroid Build Coastguard Worker return -1;
180*de1e4e89SAndroid Build Coastguard Worker } else {
181*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "index") == 0) {
182*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
183*de1e4e89SAndroid Build Coastguard Worker if (get_u32(&p.index, *argv, 10)) {
184*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "mirred: Illegal \"index\"\n");
185*de1e4e89SAndroid Build Coastguard Worker return -1;
186*de1e4e89SAndroid Build Coastguard Worker }
187*de1e4e89SAndroid Build Coastguard Worker argc--;
188*de1e4e89SAndroid Build Coastguard Worker argv++;
189*de1e4e89SAndroid Build Coastguard Worker }
190*de1e4e89SAndroid Build Coastguard Worker }
191*de1e4e89SAndroid Build Coastguard Worker }
192*de1e4e89SAndroid Build Coastguard Worker
193*de1e4e89SAndroid Build Coastguard Worker tail = NLMSG_TAIL(n);
194*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, tca_id, NULL, 0);
195*de1e4e89SAndroid Build Coastguard Worker addattr_l(n, MAX_MSG, TCA_MIRRED_PARMS, &p, sizeof(p));
196*de1e4e89SAndroid Build Coastguard Worker tail->rta_len = (void *) NLMSG_TAIL(n) - (void *) tail;
197*de1e4e89SAndroid Build Coastguard Worker
198*de1e4e89SAndroid Build Coastguard Worker *argc_p = argc;
199*de1e4e89SAndroid Build Coastguard Worker *argv_p = argv;
200*de1e4e89SAndroid Build Coastguard Worker return 0;
201*de1e4e89SAndroid Build Coastguard Worker }
202*de1e4e89SAndroid Build Coastguard Worker
203*de1e4e89SAndroid Build Coastguard Worker
204*de1e4e89SAndroid Build Coastguard Worker static int
parse_mirred(struct action_util * a,int * argc_p,char *** argv_p,int tca_id,struct nlmsghdr * n)205*de1e4e89SAndroid Build Coastguard Worker parse_mirred(struct action_util *a, int *argc_p, char ***argv_p,
206*de1e4e89SAndroid Build Coastguard Worker int tca_id, struct nlmsghdr *n)
207*de1e4e89SAndroid Build Coastguard Worker {
208*de1e4e89SAndroid Build Coastguard Worker
209*de1e4e89SAndroid Build Coastguard Worker int argc = *argc_p;
210*de1e4e89SAndroid Build Coastguard Worker char **argv = *argv_p;
211*de1e4e89SAndroid Build Coastguard Worker
212*de1e4e89SAndroid Build Coastguard Worker if (argc < 0) {
213*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "mirred bad argument count %d\n", argc);
214*de1e4e89SAndroid Build Coastguard Worker return -1;
215*de1e4e89SAndroid Build Coastguard Worker }
216*de1e4e89SAndroid Build Coastguard Worker
217*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "mirred") == 0) {
218*de1e4e89SAndroid Build Coastguard Worker NEXT_ARG();
219*de1e4e89SAndroid Build Coastguard Worker } else {
220*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "mirred bad argument %s\n", *argv);
221*de1e4e89SAndroid Build Coastguard Worker return -1;
222*de1e4e89SAndroid Build Coastguard Worker }
223*de1e4e89SAndroid Build Coastguard Worker
224*de1e4e89SAndroid Build Coastguard Worker
225*de1e4e89SAndroid Build Coastguard Worker if (matches(*argv, "egress") == 0 || matches(*argv, "ingress") == 0 ||
226*de1e4e89SAndroid Build Coastguard Worker matches(*argv, "index") == 0) {
227*de1e4e89SAndroid Build Coastguard Worker int ret = parse_direction(a, &argc, &argv, tca_id, n);
228*de1e4e89SAndroid Build Coastguard Worker
229*de1e4e89SAndroid Build Coastguard Worker if (ret == 0) {
230*de1e4e89SAndroid Build Coastguard Worker *argc_p = argc;
231*de1e4e89SAndroid Build Coastguard Worker *argv_p = argv;
232*de1e4e89SAndroid Build Coastguard Worker return 0;
233*de1e4e89SAndroid Build Coastguard Worker }
234*de1e4e89SAndroid Build Coastguard Worker
235*de1e4e89SAndroid Build Coastguard Worker } else if (matches(*argv, "help") == 0) {
236*de1e4e89SAndroid Build Coastguard Worker usage();
237*de1e4e89SAndroid Build Coastguard Worker } else {
238*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "mirred option not supported %s\n", *argv);
239*de1e4e89SAndroid Build Coastguard Worker }
240*de1e4e89SAndroid Build Coastguard Worker
241*de1e4e89SAndroid Build Coastguard Worker return -1;
242*de1e4e89SAndroid Build Coastguard Worker
243*de1e4e89SAndroid Build Coastguard Worker }
244*de1e4e89SAndroid Build Coastguard Worker
245*de1e4e89SAndroid Build Coastguard Worker static int
print_mirred(struct action_util * au,FILE * f,struct rtattr * arg)246*de1e4e89SAndroid Build Coastguard Worker print_mirred(struct action_util *au, FILE * f, struct rtattr *arg)
247*de1e4e89SAndroid Build Coastguard Worker {
248*de1e4e89SAndroid Build Coastguard Worker struct tc_mirred *p;
249*de1e4e89SAndroid Build Coastguard Worker struct rtattr *tb[TCA_MIRRED_MAX + 1];
250*de1e4e89SAndroid Build Coastguard Worker const char *dev;
251*de1e4e89SAndroid Build Coastguard Worker
252*de1e4e89SAndroid Build Coastguard Worker if (arg == NULL)
253*de1e4e89SAndroid Build Coastguard Worker return -1;
254*de1e4e89SAndroid Build Coastguard Worker
255*de1e4e89SAndroid Build Coastguard Worker parse_rtattr_nested(tb, TCA_MIRRED_MAX, arg);
256*de1e4e89SAndroid Build Coastguard Worker
257*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_MIRRED_PARMS] == NULL) {
258*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "[NULL mirred parameters]");
259*de1e4e89SAndroid Build Coastguard Worker return -1;
260*de1e4e89SAndroid Build Coastguard Worker }
261*de1e4e89SAndroid Build Coastguard Worker p = RTA_DATA(tb[TCA_MIRRED_PARMS]);
262*de1e4e89SAndroid Build Coastguard Worker
263*de1e4e89SAndroid Build Coastguard Worker /*
264*de1e4e89SAndroid Build Coastguard Worker ll_init_map(&rth);
265*de1e4e89SAndroid Build Coastguard Worker */
266*de1e4e89SAndroid Build Coastguard Worker
267*de1e4e89SAndroid Build Coastguard Worker
268*de1e4e89SAndroid Build Coastguard Worker if ((dev = ll_index_to_name(p->ifindex)) == 0) {
269*de1e4e89SAndroid Build Coastguard Worker fprintf(stderr, "Cannot find device %d\n", p->ifindex);
270*de1e4e89SAndroid Build Coastguard Worker return -1;
271*de1e4e89SAndroid Build Coastguard Worker }
272*de1e4e89SAndroid Build Coastguard Worker
273*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "mirred (%s to device %s)", mirred_n2a(p->eaction), dev);
274*de1e4e89SAndroid Build Coastguard Worker print_action_control(f, " ", p->action, "");
275*de1e4e89SAndroid Build Coastguard Worker
276*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n ");
277*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\tindex %u ref %d bind %d", p->index, p->refcnt,
278*de1e4e89SAndroid Build Coastguard Worker p->bindcnt);
279*de1e4e89SAndroid Build Coastguard Worker
280*de1e4e89SAndroid Build Coastguard Worker if (show_stats) {
281*de1e4e89SAndroid Build Coastguard Worker if (tb[TCA_MIRRED_TM]) {
282*de1e4e89SAndroid Build Coastguard Worker struct tcf_t *tm = RTA_DATA(tb[TCA_MIRRED_TM]);
283*de1e4e89SAndroid Build Coastguard Worker
284*de1e4e89SAndroid Build Coastguard Worker print_tm(f, tm);
285*de1e4e89SAndroid Build Coastguard Worker }
286*de1e4e89SAndroid Build Coastguard Worker }
287*de1e4e89SAndroid Build Coastguard Worker fprintf(f, "\n ");
288*de1e4e89SAndroid Build Coastguard Worker return 0;
289*de1e4e89SAndroid Build Coastguard Worker }
290*de1e4e89SAndroid Build Coastguard Worker
291*de1e4e89SAndroid Build Coastguard Worker struct action_util mirred_action_util = {
292*de1e4e89SAndroid Build Coastguard Worker .id = "mirred",
293*de1e4e89SAndroid Build Coastguard Worker .parse_aopt = parse_mirred,
294*de1e4e89SAndroid Build Coastguard Worker .print_aopt = print_mirred,
295*de1e4e89SAndroid Build Coastguard Worker };
296