1 /*
2 * Arturo Borrero Gonzalez <arturo@debian.org> adapted
3 * this code to libxtables for arptables-compat in 2015
4 */
5
6 #include <stdio.h>
7 #include <netdb.h>
8 #include <string.h>
9 #include <stdlib.h>
10 #include <limits.h>
11 #include <getopt.h>
12 #include <netinet/ether.h>
13 #include <xtables.h>
14 #include <linux/netfilter_arp/arpt_mangle.h>
15 #include "iptables/nft.h"
16
arpmangle_print_help(void)17 static void arpmangle_print_help(void)
18 {
19 printf(
20 "mangle target options:\n"
21 "--mangle-ip-s IP address\n"
22 "--mangle-ip-d IP address\n"
23 "--mangle-mac-s MAC address\n"
24 "--mangle-mac-d MAC address\n"
25 "--mangle-target target (DROP, CONTINUE or ACCEPT -- default is ACCEPT)\n");
26 }
27
28 /* internal use only, explicitly not covered by ARPT_MANGLE_MASK */
29 #define ARPT_MANGLE_TARGET 0x10
30
31 static const struct xt_option_entry arpmangle_opts[] = {
32 { .name = "mangle-ip-s", .id = ARPT_MANGLE_SIP, .type = XTTYPE_HOSTMASK },
33 { .name = "mangle-ip-d", .id = ARPT_MANGLE_TIP, .type = XTTYPE_HOSTMASK },
34 { .name = "mangle-mac-s", .id = ARPT_MANGLE_SDEV, .type = XTTYPE_ETHERMAC },
35 { .name = "mangle-mac-d", .id = ARPT_MANGLE_TDEV, .type = XTTYPE_ETHERMAC },
36 { .name = "mangle-target", .id = ARPT_MANGLE_TARGET, .type = XTTYPE_STRING },
37 XTOPT_TABLEEND,
38 };
39
arpmangle_init(struct xt_entry_target * target)40 static void arpmangle_init(struct xt_entry_target *target)
41 {
42 struct arpt_mangle *mangle = (struct arpt_mangle *)target->data;
43
44 mangle->target = NF_ACCEPT;
45 }
46
assert_hopts(const struct arpt_entry * e,const char * optname)47 static void assert_hopts(const struct arpt_entry *e, const char *optname)
48 {
49 if (e->arp.arhln_mask == 0)
50 xtables_error(PARAMETER_PROBLEM, "no --h-length defined");
51 if (e->arp.invflags & IPT_INV_ARPHLN)
52 xtables_error(PARAMETER_PROBLEM,
53 "! hln not allowed for --%s", optname);
54 if (e->arp.arhln != 6)
55 xtables_error(PARAMETER_PROBLEM, "only --h-length 6 supported");
56 }
57
arpmangle_parse(struct xt_option_call * cb)58 static void arpmangle_parse(struct xt_option_call *cb)
59 {
60 const struct arpt_entry *e = cb->xt_entry;
61 struct arpt_mangle *mangle = cb->data;
62
63 xtables_option_parse(cb);
64 mangle->flags |= (cb->entry->id & ARPT_MANGLE_MASK);
65 switch (cb->entry->id) {
66 case ARPT_MANGLE_SIP:
67 mangle->u_s.src_ip = cb->val.haddr.in;
68 break;
69 case ARPT_MANGLE_TIP:
70 mangle->u_t.tgt_ip = cb->val.haddr.in;
71 break;
72 case ARPT_MANGLE_SDEV:
73 assert_hopts(e, cb->entry->name);
74 memcpy(mangle->src_devaddr, cb->val.ethermac, ETH_ALEN);
75 case ARPT_MANGLE_TDEV:
76 assert_hopts(e, cb->entry->name);
77 memcpy(mangle->tgt_devaddr, cb->val.ethermac, ETH_ALEN);
78 break;
79 case ARPT_MANGLE_TARGET:
80 if (!strcmp(cb->arg, "DROP"))
81 mangle->target = NF_DROP;
82 else if (!strcmp(cb->arg, "ACCEPT"))
83 mangle->target = NF_ACCEPT;
84 else if (!strcmp(cb->arg, "CONTINUE"))
85 mangle->target = XT_CONTINUE;
86 else
87 xtables_error(PARAMETER_PROBLEM,
88 "bad target for --mangle-target");
89 break;
90 }
91 }
92
ipaddr_to(const struct in_addr * addrp,int numeric)93 static const char *ipaddr_to(const struct in_addr *addrp, int numeric)
94 {
95 if (numeric)
96 return xtables_ipaddr_to_numeric(addrp);
97 else
98 return xtables_ipaddr_to_anyname(addrp);
99 }
100
101 static void
arpmangle_print(const void * ip,const struct xt_entry_target * target,int numeric)102 arpmangle_print(const void *ip, const struct xt_entry_target *target,
103 int numeric)
104 {
105 struct arpt_mangle *m = (struct arpt_mangle *)(target->data);
106
107 if (m->flags & ARPT_MANGLE_SIP) {
108 printf(" --mangle-ip-s %s",
109 ipaddr_to(&(m->u_s.src_ip), numeric));
110 }
111 if (m->flags & ARPT_MANGLE_SDEV) {
112 printf(" --mangle-mac-s ");
113 xtables_print_mac((unsigned char *)m->src_devaddr);
114 }
115 if (m->flags & ARPT_MANGLE_TIP) {
116 printf(" --mangle-ip-d %s",
117 ipaddr_to(&(m->u_t.tgt_ip), numeric));
118 }
119 if (m->flags & ARPT_MANGLE_TDEV) {
120 printf(" --mangle-mac-d ");
121 xtables_print_mac((unsigned char *)m->tgt_devaddr);
122 }
123 if (m->target != NF_ACCEPT) {
124 printf(" --mangle-target %s",
125 m->target == NF_DROP ? "DROP" : "CONTINUE");
126 }
127 }
128
arpmangle_save(const void * ip,const struct xt_entry_target * target)129 static void arpmangle_save(const void *ip, const struct xt_entry_target *target)
130 {
131 arpmangle_print(ip, target, 0);
132 }
133
print_devaddr_xlate(const char * macaddress,struct xt_xlate * xl)134 static void print_devaddr_xlate(const char *macaddress, struct xt_xlate *xl)
135 {
136 unsigned int i;
137
138 xt_xlate_add(xl, "%02x", macaddress[0]);
139 for (i = 1; i < ETH_ALEN; ++i)
140 xt_xlate_add(xl, ":%02x", macaddress[i]);
141 }
142
arpmangle_xlate(struct xt_xlate * xl,const struct xt_xlate_tg_params * params)143 static int arpmangle_xlate(struct xt_xlate *xl,
144 const struct xt_xlate_tg_params *params)
145 {
146 const struct arpt_mangle *m = (const void *)params->target->data;
147
148 if (m->flags & ARPT_MANGLE_SIP)
149 xt_xlate_add(xl, "arp saddr ip set %s ",
150 xtables_ipaddr_to_numeric(&m->u_s.src_ip));
151
152 if (m->flags & ARPT_MANGLE_SDEV) {
153 xt_xlate_add(xl, "arp %caddr ether set ", 's');
154 print_devaddr_xlate(m->src_devaddr, xl);
155 }
156
157 if (m->flags & ARPT_MANGLE_TIP)
158 xt_xlate_add(xl, "arp daddr ip set %s ",
159 xtables_ipaddr_to_numeric(&m->u_t.tgt_ip));
160
161 if (m->flags & ARPT_MANGLE_TDEV) {
162 xt_xlate_add(xl, "arp %caddr ether set ", 'd');
163 print_devaddr_xlate(m->tgt_devaddr, xl);
164 }
165
166 switch (m->target) {
167 case NF_ACCEPT:
168 xt_xlate_add(xl, "accept");
169 break;
170 case NF_DROP:
171 xt_xlate_add(xl, "drop");
172 break;
173 default:
174 break;
175 }
176
177 return 1;
178 }
179
180 static struct xtables_target arpmangle_target = {
181 .name = "mangle",
182 .revision = 0,
183 .version = XTABLES_VERSION,
184 .family = NFPROTO_ARP,
185 .size = XT_ALIGN(sizeof(struct arpt_mangle)),
186 .userspacesize = XT_ALIGN(sizeof(struct arpt_mangle)),
187 .help = arpmangle_print_help,
188 .init = arpmangle_init,
189 .x6_parse = arpmangle_parse,
190 .print = arpmangle_print,
191 .save = arpmangle_save,
192 .x6_options = arpmangle_opts,
193 .xlate = arpmangle_xlate,
194 };
195
_init(void)196 void _init(void)
197 {
198 xtables_register_target(&arpmangle_target);
199 }
200