1*a71a9546SAutomerger Merge Worker #include <stdio.h>
2*a71a9546SAutomerger Merge Worker #include <string.h>
3*a71a9546SAutomerger Merge Worker #include <stdlib.h>
4*a71a9546SAutomerger Merge Worker #include <xtables.h>
5*a71a9546SAutomerger Merge Worker #include <linux/netfilter_ipv6/ip6t_rt.h>
6*a71a9546SAutomerger Merge Worker #include <arpa/inet.h>
7*a71a9546SAutomerger Merge Worker
8*a71a9546SAutomerger Merge Worker enum {
9*a71a9546SAutomerger Merge Worker O_RT_TYPE = 0,
10*a71a9546SAutomerger Merge Worker O_RT_SEGSLEFT,
11*a71a9546SAutomerger Merge Worker O_RT_LEN,
12*a71a9546SAutomerger Merge Worker O_RT0RES,
13*a71a9546SAutomerger Merge Worker O_RT0ADDRS,
14*a71a9546SAutomerger Merge Worker O_RT0NSTRICT,
15*a71a9546SAutomerger Merge Worker F_RT_TYPE = 1 << O_RT_TYPE,
16*a71a9546SAutomerger Merge Worker F_RT0ADDRS = 1 << O_RT0ADDRS,
17*a71a9546SAutomerger Merge Worker };
18*a71a9546SAutomerger Merge Worker
rt_help(void)19*a71a9546SAutomerger Merge Worker static void rt_help(void)
20*a71a9546SAutomerger Merge Worker {
21*a71a9546SAutomerger Merge Worker printf(
22*a71a9546SAutomerger Merge Worker "rt match options:\n"
23*a71a9546SAutomerger Merge Worker "[!] --rt-type type match the type\n"
24*a71a9546SAutomerger Merge Worker "[!] --rt-segsleft num[:num] match the Segments Left field (range)\n"
25*a71a9546SAutomerger Merge Worker "[!] --rt-len length total length of this header\n"
26*a71a9546SAutomerger Merge Worker " --rt-0-res check the reserved field too (type 0)\n"
27*a71a9546SAutomerger Merge Worker " --rt-0-addrs ADDR[,ADDR...] Type=0 addresses (list, max: %d)\n"
28*a71a9546SAutomerger Merge Worker " --rt-0-not-strict List of Type=0 addresses not a strict list\n",
29*a71a9546SAutomerger Merge Worker IP6T_RT_HOPS);
30*a71a9546SAutomerger Merge Worker }
31*a71a9546SAutomerger Merge Worker
32*a71a9546SAutomerger Merge Worker #define s struct ip6t_rt
33*a71a9546SAutomerger Merge Worker static const struct xt_option_entry rt_opts[] = {
34*a71a9546SAutomerger Merge Worker {.name = "rt-type", .id = O_RT_TYPE, .type = XTTYPE_UINT32,
35*a71a9546SAutomerger Merge Worker .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, rt_type)},
36*a71a9546SAutomerger Merge Worker {.name = "rt-segsleft", .id = O_RT_SEGSLEFT, .type = XTTYPE_UINT32RC,
37*a71a9546SAutomerger Merge Worker .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, segsleft)},
38*a71a9546SAutomerger Merge Worker {.name = "rt-len", .id = O_RT_LEN, .type = XTTYPE_UINT32,
39*a71a9546SAutomerger Merge Worker .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)},
40*a71a9546SAutomerger Merge Worker {.name = "rt-0-res", .id = O_RT0RES, .type = XTTYPE_NONE},
41*a71a9546SAutomerger Merge Worker {.name = "rt-0-addrs", .id = O_RT0ADDRS, .type = XTTYPE_STRING},
42*a71a9546SAutomerger Merge Worker {.name = "rt-0-not-strict", .id = O_RT0NSTRICT, .type = XTTYPE_NONE},
43*a71a9546SAutomerger Merge Worker XTOPT_TABLEEND,
44*a71a9546SAutomerger Merge Worker };
45*a71a9546SAutomerger Merge Worker #undef s
46*a71a9546SAutomerger Merge Worker
47*a71a9546SAutomerger Merge Worker static const char *
addr_to_numeric(const struct in6_addr * addrp)48*a71a9546SAutomerger Merge Worker addr_to_numeric(const struct in6_addr *addrp)
49*a71a9546SAutomerger Merge Worker {
50*a71a9546SAutomerger Merge Worker static char buf[50+1];
51*a71a9546SAutomerger Merge Worker return inet_ntop(AF_INET6, addrp, buf, sizeof(buf));
52*a71a9546SAutomerger Merge Worker }
53*a71a9546SAutomerger Merge Worker
54*a71a9546SAutomerger Merge Worker static struct in6_addr *
numeric_to_addr(const char * num)55*a71a9546SAutomerger Merge Worker numeric_to_addr(const char *num)
56*a71a9546SAutomerger Merge Worker {
57*a71a9546SAutomerger Merge Worker static struct in6_addr ap;
58*a71a9546SAutomerger Merge Worker int err;
59*a71a9546SAutomerger Merge Worker
60*a71a9546SAutomerger Merge Worker if ((err=inet_pton(AF_INET6, num, &ap)) == 1)
61*a71a9546SAutomerger Merge Worker return ≈
62*a71a9546SAutomerger Merge Worker #ifdef DEBUG
63*a71a9546SAutomerger Merge Worker fprintf(stderr, "\nnumeric2addr: %d\n", err);
64*a71a9546SAutomerger Merge Worker #endif
65*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM, "bad address: %s", num);
66*a71a9546SAutomerger Merge Worker
67*a71a9546SAutomerger Merge Worker return (struct in6_addr *)NULL;
68*a71a9546SAutomerger Merge Worker }
69*a71a9546SAutomerger Merge Worker
70*a71a9546SAutomerger Merge Worker
71*a71a9546SAutomerger Merge Worker static int
parse_addresses(const char * addrstr,struct in6_addr * addrp)72*a71a9546SAutomerger Merge Worker parse_addresses(const char *addrstr, struct in6_addr *addrp)
73*a71a9546SAutomerger Merge Worker {
74*a71a9546SAutomerger Merge Worker char *buffer, *cp, *next;
75*a71a9546SAutomerger Merge Worker unsigned int i;
76*a71a9546SAutomerger Merge Worker
77*a71a9546SAutomerger Merge Worker buffer = xtables_strdup(addrstr);
78*a71a9546SAutomerger Merge Worker
79*a71a9546SAutomerger Merge Worker for (cp=buffer, i=0; cp && i<IP6T_RT_HOPS; cp=next,i++)
80*a71a9546SAutomerger Merge Worker {
81*a71a9546SAutomerger Merge Worker next=strchr(cp, ',');
82*a71a9546SAutomerger Merge Worker if (next) *next++='\0';
83*a71a9546SAutomerger Merge Worker memcpy(&(addrp[i]), numeric_to_addr(cp), sizeof(struct in6_addr));
84*a71a9546SAutomerger Merge Worker #if DEBUG
85*a71a9546SAutomerger Merge Worker printf("addr str: %s\n", cp);
86*a71a9546SAutomerger Merge Worker printf("addr ip6: %s\n", addr_to_numeric((numeric_to_addr(cp))));
87*a71a9546SAutomerger Merge Worker printf("addr [%d]: %s\n", i, addr_to_numeric(&(addrp[i])));
88*a71a9546SAutomerger Merge Worker #endif
89*a71a9546SAutomerger Merge Worker }
90*a71a9546SAutomerger Merge Worker if (cp) xtables_error(PARAMETER_PROBLEM, "too many addresses specified");
91*a71a9546SAutomerger Merge Worker
92*a71a9546SAutomerger Merge Worker free(buffer);
93*a71a9546SAutomerger Merge Worker
94*a71a9546SAutomerger Merge Worker #if DEBUG
95*a71a9546SAutomerger Merge Worker printf("addr nr: %d\n", i);
96*a71a9546SAutomerger Merge Worker #endif
97*a71a9546SAutomerger Merge Worker
98*a71a9546SAutomerger Merge Worker return i;
99*a71a9546SAutomerger Merge Worker }
100*a71a9546SAutomerger Merge Worker
rt_init(struct xt_entry_match * m)101*a71a9546SAutomerger Merge Worker static void rt_init(struct xt_entry_match *m)
102*a71a9546SAutomerger Merge Worker {
103*a71a9546SAutomerger Merge Worker struct ip6t_rt *rtinfo = (void *)m->data;
104*a71a9546SAutomerger Merge Worker
105*a71a9546SAutomerger Merge Worker rtinfo->segsleft[1] = ~0U;
106*a71a9546SAutomerger Merge Worker }
107*a71a9546SAutomerger Merge Worker
rt_parse(struct xt_option_call * cb)108*a71a9546SAutomerger Merge Worker static void rt_parse(struct xt_option_call *cb)
109*a71a9546SAutomerger Merge Worker {
110*a71a9546SAutomerger Merge Worker struct ip6t_rt *rtinfo = cb->data;
111*a71a9546SAutomerger Merge Worker
112*a71a9546SAutomerger Merge Worker xtables_option_parse(cb);
113*a71a9546SAutomerger Merge Worker switch (cb->entry->id) {
114*a71a9546SAutomerger Merge Worker case O_RT_TYPE:
115*a71a9546SAutomerger Merge Worker if (cb->invert)
116*a71a9546SAutomerger Merge Worker rtinfo->invflags |= IP6T_RT_INV_TYP;
117*a71a9546SAutomerger Merge Worker rtinfo->flags |= IP6T_RT_TYP;
118*a71a9546SAutomerger Merge Worker break;
119*a71a9546SAutomerger Merge Worker case O_RT_SEGSLEFT:
120*a71a9546SAutomerger Merge Worker if (cb->nvals == 1)
121*a71a9546SAutomerger Merge Worker rtinfo->segsleft[1] = rtinfo->segsleft[0];
122*a71a9546SAutomerger Merge Worker if (cb->invert)
123*a71a9546SAutomerger Merge Worker rtinfo->invflags |= IP6T_RT_INV_SGS;
124*a71a9546SAutomerger Merge Worker rtinfo->flags |= IP6T_RT_SGS;
125*a71a9546SAutomerger Merge Worker break;
126*a71a9546SAutomerger Merge Worker case O_RT_LEN:
127*a71a9546SAutomerger Merge Worker if (cb->invert)
128*a71a9546SAutomerger Merge Worker rtinfo->invflags |= IP6T_RT_INV_LEN;
129*a71a9546SAutomerger Merge Worker rtinfo->flags |= IP6T_RT_LEN;
130*a71a9546SAutomerger Merge Worker break;
131*a71a9546SAutomerger Merge Worker case O_RT0RES:
132*a71a9546SAutomerger Merge Worker if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
133*a71a9546SAutomerger Merge Worker rtinfo->invflags & IP6T_RT_INV_TYP)
134*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
135*a71a9546SAutomerger Merge Worker "`--rt-type 0' required before `--rt-0-res'");
136*a71a9546SAutomerger Merge Worker rtinfo->flags |= IP6T_RT_RES;
137*a71a9546SAutomerger Merge Worker break;
138*a71a9546SAutomerger Merge Worker case O_RT0ADDRS:
139*a71a9546SAutomerger Merge Worker if (!(cb->xflags & F_RT_TYPE) || rtinfo->rt_type != 0 ||
140*a71a9546SAutomerger Merge Worker rtinfo->invflags & IP6T_RT_INV_TYP)
141*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
142*a71a9546SAutomerger Merge Worker "`--rt-type 0' required before `--rt-0-addrs'");
143*a71a9546SAutomerger Merge Worker rtinfo->addrnr = parse_addresses(cb->arg, rtinfo->addrs);
144*a71a9546SAutomerger Merge Worker rtinfo->flags |= IP6T_RT_FST;
145*a71a9546SAutomerger Merge Worker break;
146*a71a9546SAutomerger Merge Worker case O_RT0NSTRICT:
147*a71a9546SAutomerger Merge Worker if (!(cb->xflags & F_RT0ADDRS))
148*a71a9546SAutomerger Merge Worker xtables_error(PARAMETER_PROBLEM,
149*a71a9546SAutomerger Merge Worker "`--rt-0-addr ...' required before `--rt-0-not-strict'");
150*a71a9546SAutomerger Merge Worker rtinfo->flags |= IP6T_RT_FST_NSTRICT;
151*a71a9546SAutomerger Merge Worker break;
152*a71a9546SAutomerger Merge Worker }
153*a71a9546SAutomerger Merge Worker }
154*a71a9546SAutomerger Merge Worker
155*a71a9546SAutomerger Merge Worker static void
print_nums(const char * name,uint32_t min,uint32_t max,int invert)156*a71a9546SAutomerger Merge Worker print_nums(const char *name, uint32_t min, uint32_t max,
157*a71a9546SAutomerger Merge Worker int invert)
158*a71a9546SAutomerger Merge Worker {
159*a71a9546SAutomerger Merge Worker const char *inv = invert ? "!" : "";
160*a71a9546SAutomerger Merge Worker
161*a71a9546SAutomerger Merge Worker if (min != 0 || max != 0xFFFFFFFF || invert) {
162*a71a9546SAutomerger Merge Worker printf(" %s", name);
163*a71a9546SAutomerger Merge Worker if (min == max) {
164*a71a9546SAutomerger Merge Worker printf(":%s", inv);
165*a71a9546SAutomerger Merge Worker printf("%u", min);
166*a71a9546SAutomerger Merge Worker } else {
167*a71a9546SAutomerger Merge Worker printf("s:%s", inv);
168*a71a9546SAutomerger Merge Worker printf("%u",min);
169*a71a9546SAutomerger Merge Worker printf(":");
170*a71a9546SAutomerger Merge Worker printf("%u",max);
171*a71a9546SAutomerger Merge Worker }
172*a71a9546SAutomerger Merge Worker }
173*a71a9546SAutomerger Merge Worker }
174*a71a9546SAutomerger Merge Worker
175*a71a9546SAutomerger Merge Worker static void
print_addresses(unsigned int addrnr,struct in6_addr * addrp)176*a71a9546SAutomerger Merge Worker print_addresses(unsigned int addrnr, struct in6_addr *addrp)
177*a71a9546SAutomerger Merge Worker {
178*a71a9546SAutomerger Merge Worker unsigned int i;
179*a71a9546SAutomerger Merge Worker
180*a71a9546SAutomerger Merge Worker for(i=0; i<addrnr; i++){
181*a71a9546SAutomerger Merge Worker printf("%c%s", (i==0)?' ':',', addr_to_numeric(&(addrp[i])));
182*a71a9546SAutomerger Merge Worker }
183*a71a9546SAutomerger Merge Worker }
184*a71a9546SAutomerger Merge Worker
rt_print(const void * ip,const struct xt_entry_match * match,int numeric)185*a71a9546SAutomerger Merge Worker static void rt_print(const void *ip, const struct xt_entry_match *match,
186*a71a9546SAutomerger Merge Worker int numeric)
187*a71a9546SAutomerger Merge Worker {
188*a71a9546SAutomerger Merge Worker const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
189*a71a9546SAutomerger Merge Worker
190*a71a9546SAutomerger Merge Worker printf(" rt");
191*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_TYP)
192*a71a9546SAutomerger Merge Worker printf(" type:%s%d", rtinfo->invflags & IP6T_RT_INV_TYP ? "!" : "",
193*a71a9546SAutomerger Merge Worker rtinfo->rt_type);
194*a71a9546SAutomerger Merge Worker print_nums("segsleft", rtinfo->segsleft[0], rtinfo->segsleft[1],
195*a71a9546SAutomerger Merge Worker rtinfo->invflags & IP6T_RT_INV_SGS);
196*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_LEN) {
197*a71a9546SAutomerger Merge Worker printf(" length");
198*a71a9546SAutomerger Merge Worker printf(":%s", rtinfo->invflags & IP6T_RT_INV_LEN ? "!" : "");
199*a71a9546SAutomerger Merge Worker printf("%u", rtinfo->hdrlen);
200*a71a9546SAutomerger Merge Worker }
201*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_RES) printf(" reserved");
202*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_FST) printf(" 0-addrs");
203*a71a9546SAutomerger Merge Worker print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
204*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" 0-not-strict");
205*a71a9546SAutomerger Merge Worker if (rtinfo->invflags & ~IP6T_RT_INV_MASK)
206*a71a9546SAutomerger Merge Worker printf(" Unknown invflags: 0x%X",
207*a71a9546SAutomerger Merge Worker rtinfo->invflags & ~IP6T_RT_INV_MASK);
208*a71a9546SAutomerger Merge Worker }
209*a71a9546SAutomerger Merge Worker
rt_save(const void * ip,const struct xt_entry_match * match)210*a71a9546SAutomerger Merge Worker static void rt_save(const void *ip, const struct xt_entry_match *match)
211*a71a9546SAutomerger Merge Worker {
212*a71a9546SAutomerger Merge Worker const struct ip6t_rt *rtinfo = (struct ip6t_rt *)match->data;
213*a71a9546SAutomerger Merge Worker
214*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_TYP) {
215*a71a9546SAutomerger Merge Worker printf("%s --rt-type %u",
216*a71a9546SAutomerger Merge Worker (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !" : "",
217*a71a9546SAutomerger Merge Worker rtinfo->rt_type);
218*a71a9546SAutomerger Merge Worker }
219*a71a9546SAutomerger Merge Worker
220*a71a9546SAutomerger Merge Worker if (!(rtinfo->segsleft[0] == 0
221*a71a9546SAutomerger Merge Worker && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
222*a71a9546SAutomerger Merge Worker printf("%s --rt-segsleft ",
223*a71a9546SAutomerger Merge Worker (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !" : "");
224*a71a9546SAutomerger Merge Worker if (rtinfo->segsleft[0]
225*a71a9546SAutomerger Merge Worker != rtinfo->segsleft[1])
226*a71a9546SAutomerger Merge Worker printf("%u:%u",
227*a71a9546SAutomerger Merge Worker rtinfo->segsleft[0],
228*a71a9546SAutomerger Merge Worker rtinfo->segsleft[1]);
229*a71a9546SAutomerger Merge Worker else
230*a71a9546SAutomerger Merge Worker printf("%u",
231*a71a9546SAutomerger Merge Worker rtinfo->segsleft[0]);
232*a71a9546SAutomerger Merge Worker }
233*a71a9546SAutomerger Merge Worker
234*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_LEN) {
235*a71a9546SAutomerger Merge Worker printf("%s --rt-len %u",
236*a71a9546SAutomerger Merge Worker (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !" : "",
237*a71a9546SAutomerger Merge Worker rtinfo->hdrlen);
238*a71a9546SAutomerger Merge Worker }
239*a71a9546SAutomerger Merge Worker
240*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_RES) printf(" --rt-0-res");
241*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_FST) printf(" --rt-0-addrs");
242*a71a9546SAutomerger Merge Worker print_addresses(rtinfo->addrnr, (struct in6_addr *)rtinfo->addrs);
243*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_FST_NSTRICT) printf(" --rt-0-not-strict");
244*a71a9546SAutomerger Merge Worker
245*a71a9546SAutomerger Merge Worker }
246*a71a9546SAutomerger Merge Worker
rt_xlate(struct xt_xlate * xl,const struct xt_xlate_mt_params * params)247*a71a9546SAutomerger Merge Worker static int rt_xlate(struct xt_xlate *xl,
248*a71a9546SAutomerger Merge Worker const struct xt_xlate_mt_params *params)
249*a71a9546SAutomerger Merge Worker {
250*a71a9546SAutomerger Merge Worker const struct ip6t_rt *rtinfo = (struct ip6t_rt *)params->match->data;
251*a71a9546SAutomerger Merge Worker
252*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_TYP) {
253*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "rt type%s %u",
254*a71a9546SAutomerger Merge Worker (rtinfo->invflags & IP6T_RT_INV_TYP) ? " !=" : "",
255*a71a9546SAutomerger Merge Worker rtinfo->rt_type);
256*a71a9546SAutomerger Merge Worker }
257*a71a9546SAutomerger Merge Worker
258*a71a9546SAutomerger Merge Worker if (!(rtinfo->segsleft[0] == 0 && rtinfo->segsleft[1] == 0xFFFFFFFF)) {
259*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "rt seg-left%s ",
260*a71a9546SAutomerger Merge Worker (rtinfo->invflags & IP6T_RT_INV_SGS) ? " !=" : "");
261*a71a9546SAutomerger Merge Worker
262*a71a9546SAutomerger Merge Worker if (rtinfo->segsleft[0] != rtinfo->segsleft[1])
263*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "%u-%u", rtinfo->segsleft[0],
264*a71a9546SAutomerger Merge Worker rtinfo->segsleft[1]);
265*a71a9546SAutomerger Merge Worker else
266*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "%u", rtinfo->segsleft[0]);
267*a71a9546SAutomerger Merge Worker }
268*a71a9546SAutomerger Merge Worker
269*a71a9546SAutomerger Merge Worker if (rtinfo->flags & IP6T_RT_LEN) {
270*a71a9546SAutomerger Merge Worker xt_xlate_add(xl, "rt hdrlength%s %u",
271*a71a9546SAutomerger Merge Worker (rtinfo->invflags & IP6T_RT_INV_LEN) ? " !=" : "",
272*a71a9546SAutomerger Merge Worker rtinfo->hdrlen);
273*a71a9546SAutomerger Merge Worker }
274*a71a9546SAutomerger Merge Worker
275*a71a9546SAutomerger Merge Worker if (rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST | IP6T_RT_FST_NSTRICT))
276*a71a9546SAutomerger Merge Worker return 0;
277*a71a9546SAutomerger Merge Worker
278*a71a9546SAutomerger Merge Worker return 1;
279*a71a9546SAutomerger Merge Worker }
280*a71a9546SAutomerger Merge Worker
281*a71a9546SAutomerger Merge Worker static struct xtables_match rt_mt6_reg = {
282*a71a9546SAutomerger Merge Worker .name = "rt",
283*a71a9546SAutomerger Merge Worker .version = XTABLES_VERSION,
284*a71a9546SAutomerger Merge Worker .family = NFPROTO_IPV6,
285*a71a9546SAutomerger Merge Worker .size = XT_ALIGN(sizeof(struct ip6t_rt)),
286*a71a9546SAutomerger Merge Worker .userspacesize = XT_ALIGN(sizeof(struct ip6t_rt)),
287*a71a9546SAutomerger Merge Worker .help = rt_help,
288*a71a9546SAutomerger Merge Worker .init = rt_init,
289*a71a9546SAutomerger Merge Worker .x6_parse = rt_parse,
290*a71a9546SAutomerger Merge Worker .print = rt_print,
291*a71a9546SAutomerger Merge Worker .save = rt_save,
292*a71a9546SAutomerger Merge Worker .x6_options = rt_opts,
293*a71a9546SAutomerger Merge Worker .xlate = rt_xlate,
294*a71a9546SAutomerger Merge Worker };
295*a71a9546SAutomerger Merge Worker
296*a71a9546SAutomerger Merge Worker void
_init(void)297*a71a9546SAutomerger Merge Worker _init(void)
298*a71a9546SAutomerger Merge Worker {
299*a71a9546SAutomerger Merge Worker xtables_register_match(&rt_mt6_reg);
300*a71a9546SAutomerger Merge Worker }
301