Fix build break in 64bit architectures
[platform/upstream/iproute2.git] / tc / em_ipt.c
1 /*
2  * em_ipt.c             IPtables extensions matching Ematch
3  *
4  * (C) 2018 Eyal Birger <eyal.birger@gmail.com>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  */
10
11 #include <getopt.h>
12
13 #include <linux/tc_ematch/tc_em_ipt.h>
14 #include <linux/pkt_cls.h>
15 #include <xtables.h>
16 #include "m_ematch.h"
17
18 static void em_ipt_print_usage(FILE *fd)
19 {
20         fprintf(fd,
21                 "Usage: ipt([-6] -m MATCH_NAME [MATCH_OPTS])\n"
22                 "Example: 'ipt(-m policy --reqid 1 --pol ipsec --dir in)'\n");
23 }
24
25 static struct option original_opts[] = {
26         {
27                 .name = "match",
28                 .has_arg = 1,
29                 .val = 'm'
30         },
31         {
32                 .name = "ipv6",
33                 .val = '6'
34         },
35         {}
36 };
37
38 static struct xtables_globals em_tc_ipt_globals = {
39         .option_offset = 0,
40         .program_name = "tc-em-ipt",
41         .program_version = "0.1",
42         .orig_opts = original_opts,
43         .opts = original_opts,
44 #if (XTABLES_VERSION_CODE >= 11)
45         .compat_rev = xtables_compatible_revision,
46 #endif
47 };
48
49 static struct xt_entry_match *fake_xt_entry_match(int data_size, void *data)
50 {
51         struct xt_entry_match *m;
52
53         m = xtables_calloc(1, XT_ALIGN(sizeof(*m)) + data_size);
54         if (!m)
55                 return NULL;
56
57         if (data)
58                 memcpy(m->data, data, data_size);
59
60         m->u.user.match_size = data_size;
61         return m;
62 }
63
64 static void scrub_match(struct xtables_match *match)
65 {
66         match->mflags = 0;
67         free(match->m);
68         match->m = NULL;
69 }
70
71 /* IPv4 and IPv6 share the same hooking enumeration */
72 #define HOOK_PRE_ROUTING 0
73 #define HOOK_POST_ROUTING 4
74
75 static __u32 em_ipt_hook(struct nlmsghdr *n)
76 {
77         struct tcmsg *t = NLMSG_DATA(n);
78
79         if (t->tcm_parent != TC_H_ROOT &&
80             t->tcm_parent == TC_H_MAJ(TC_H_INGRESS))
81                 return HOOK_PRE_ROUTING;
82
83         return HOOK_POST_ROUTING;
84 }
85
86 static int em_ipt_parse_eopt_argv(struct nlmsghdr *n,
87                                   struct tcf_ematch_hdr *hdr,
88                                   int argc, char **argv)
89 {
90         struct xtables_globals tmp_tcipt_globals = em_tc_ipt_globals;
91         struct xtables_match *match = NULL;
92         __u8 nfproto = NFPROTO_IPV4;
93
94         while (1) {
95                 struct option *opts;
96                 int c;
97
98                 c = getopt_long(argc, argv, "6m:", tmp_tcipt_globals.opts,
99                                 NULL);
100                 if (c == -1)
101                         break;
102
103                 switch (c) {
104                 case 'm':
105                         xtables_init_all(&tmp_tcipt_globals, nfproto);
106
107                         match = xtables_find_match(optarg, XTF_TRY_LOAD, NULL);
108                         if (!match || !match->x6_parse) {
109                                 fprintf(stderr, " failed to find match %s\n\n",
110                                         optarg);
111                                 return -1;
112                         }
113
114                         match->m = fake_xt_entry_match(match->size, NULL);
115                         if (!match->m) {
116                                 printf(" %s error\n", match->name);
117                                 return -1;
118                         }
119
120                         if (match->init)
121                                 match->init(match->m);
122
123                         opts = xtables_options_xfrm(tmp_tcipt_globals.orig_opts,
124                                                     tmp_tcipt_globals.opts,
125                                                     match->x6_options,
126                                                     &match->option_offset);
127                         if (!opts) {
128                                 scrub_match(match);
129                                 return -1;
130                         }
131
132                         tmp_tcipt_globals.opts = opts;
133                         break;
134
135                 case '6':
136                         nfproto = NFPROTO_IPV6;
137                         break;
138
139                 default:
140                         if (!match) {
141                                 fprintf(stderr, "failed to find match %s\n\n",
142                                         optarg);
143                                 return -1;
144
145                         }
146                         xtables_option_mpcall(c, argv, 0, match, NULL);
147                         break;
148                 }
149         }
150
151         if (!match) {
152                 fprintf(stderr, " failed to parse parameters (%s)\n", *argv);
153                 return -1;
154         }
155
156         /* check that we passed the correct parameters to the match */
157         xtables_option_mfcall(match);
158
159         addraw_l(n, MAX_MSG, hdr, sizeof(*hdr));
160         addattr32(n, MAX_MSG, TCA_EM_IPT_HOOK, em_ipt_hook(n));
161         addattrstrz(n, MAX_MSG, TCA_EM_IPT_MATCH_NAME, match->name);
162         addattr8(n, MAX_MSG, TCA_EM_IPT_MATCH_REVISION, match->revision);
163         addattr8(n, MAX_MSG, TCA_EM_IPT_NFPROTO, nfproto);
164         addattr_l(n, MAX_MSG, TCA_EM_IPT_MATCH_DATA, match->m->data,
165                   match->size);
166
167         xtables_free_opts(1);
168
169         scrub_match(match);
170         return 0;
171 }
172
173 static int em_ipt_print_epot(FILE *fd, struct tcf_ematch_hdr *hdr, void *data,
174                              int data_len)
175 {
176         struct rtattr *tb[TCA_EM_IPT_MAX + 1];
177         struct xtables_match *match;
178         const char *mname;
179         __u8 nfproto;
180
181         if (parse_rtattr(tb, TCA_EM_IPT_MAX, data, data_len) < 0)
182                 return -1;
183
184         nfproto = rta_getattr_u8(tb[TCA_EM_IPT_NFPROTO]);
185
186         xtables_init_all(&em_tc_ipt_globals, nfproto);
187
188         mname = rta_getattr_str(tb[TCA_EM_IPT_MATCH_NAME]);
189         match = xtables_find_match(mname, XTF_TRY_LOAD, NULL);
190         if (!match)
191                 return -1;
192
193         match->m = fake_xt_entry_match(RTA_PAYLOAD(tb[TCA_EM_IPT_MATCH_DATA]),
194                                        RTA_DATA(tb[TCA_EM_IPT_MATCH_DATA]));
195         if (!match->m)
196                 return -1;
197
198         match->print(NULL, match->m, 0);
199
200         scrub_match(match);
201         return 0;
202 }
203
204 struct ematch_util ipt_ematch_util = {
205         .kind = "ipt",
206         .kind_num = TCF_EM_IPT,
207         .parse_eopt_argv = em_ipt_parse_eopt_argv,
208         .print_eopt = em_ipt_print_epot,
209         .print_usage = em_ipt_print_usage
210 };