1 /* Library which manipulates firewall rules. Version 0.1. */
3 /* Architecture of firewall rules is as follows:
5 * Chains go INPUT, FORWARD, OUTPUT then user chains.
6 * Each user chain starts with an ERROR node.
7 * Every chain ends with an unconditional jump: a RETURN for user chains,
8 * and a POLICY for built-ins.
11 /* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See
12 COPYING for details). */
20 #include <arpa/inet.h>
22 #ifdef DEBUG_CONNTRACK
26 #if !defined(__GLIBC__) || (__GLIBC__ < 2)
27 typedef unsigned int socklen_t
;
30 #include "libiptc/libip6tc.h"
32 #define HOOK_PRE_ROUTING NF_IP6_PRE_ROUTING
33 #define HOOK_LOCAL_IN NF_IP6_LOCAL_IN
34 #define HOOK_FORWARD NF_IP6_FORWARD
35 #define HOOK_LOCAL_OUT NF_IP6_LOCAL_OUT
36 #define HOOK_POST_ROUTING NF_IP6_POST_ROUTING
38 #define STRUCT_ENTRY_TARGET struct ip6t_entry_target
39 #define STRUCT_ENTRY struct ip6t_entry
40 #define STRUCT_ENTRY_MATCH struct ip6t_entry_match
41 #define STRUCT_GETINFO struct ip6t_getinfo
42 #define STRUCT_GET_ENTRIES struct ip6t_get_entries
43 #define STRUCT_COUNTERS struct ip6t_counters
44 #define STRUCT_COUNTERS_INFO struct ip6t_counters_info
45 #define STRUCT_STANDARD_TARGET struct ip6t_standard_target
46 #define STRUCT_REPLACE struct ip6t_replace
48 #define STRUCT_TC_HANDLE struct ip6tc_handle
49 #define TC_HANDLE_T ip6tc_handle_t
51 #define ENTRY_ITERATE IP6T_ENTRY_ITERATE
52 #define TABLE_MAXNAMELEN IP6T_TABLE_MAXNAMELEN
53 #define FUNCTION_MAXNAMELEN IP6T_FUNCTION_MAXNAMELEN
55 #define GET_TARGET ip6t_get_target
57 #define ERROR_TARGET IP6T_ERROR_TARGET
58 #define NUMHOOKS NF_IP6_NUMHOOKS
60 #define IPT_CHAINLABEL ip6t_chainlabel
62 #define TC_DUMP_ENTRIES dump_entries6
63 #define TC_IS_CHAIN ip6tc_is_chain
64 #define TC_FIRST_CHAIN ip6tc_first_chain
65 #define TC_NEXT_CHAIN ip6tc_next_chain
66 #define TC_FIRST_RULE ip6tc_first_rule
67 #define TC_NEXT_RULE ip6tc_next_rule
68 #define TC_GET_TARGET ip6tc_get_target
69 #define TC_BUILTIN ip6tc_builtin
70 #define TC_GET_POLICY ip6tc_get_policy
71 #define TC_INSERT_ENTRY ip6tc_insert_entry
72 #define TC_REPLACE_ENTRY ip6tc_replace_entry
73 #define TC_APPEND_ENTRY ip6tc_append_entry
74 #define TC_DELETE_ENTRY ip6tc_delete_entry
75 #define TC_DELETE_NUM_ENTRY ip6tc_delete_num_entry
76 #define TC_CHECK_PACKET ip6tc_check_packet
77 #define TC_FLUSH_ENTRIES ip6tc_flush_entries
78 #define TC_ZERO_ENTRIES ip6tc_zero_entries
79 #define TC_ZERO_COUNTER ip6tc_zero_counter
80 #define TC_READ_COUNTER ip6tc_read_counter
81 #define TC_SET_COUNTER ip6tc_set_counter
82 #define TC_CREATE_CHAIN ip6tc_create_chain
83 #define TC_GET_REFERENCES ip6tc_get_references
84 #define TC_DELETE_CHAIN ip6tc_delete_chain
85 #define TC_RENAME_CHAIN ip6tc_rename_chain
86 #define TC_SET_POLICY ip6tc_set_policy
87 #define TC_GET_RAW_SOCKET ip6tc_get_raw_socket
88 #define TC_INIT ip6tc_init
89 #define TC_FREE ip6tc_free
90 #define TC_COMMIT ip6tc_commit
91 #define TC_STRERROR ip6tc_strerror
92 #define TC_NUM_RULES ip6tc_num_rules
93 #define TC_GET_RULE ip6tc_get_rule
95 #define TC_AF AF_INET6
96 #define TC_IPPROTO IPPROTO_IPV6
98 #define SO_SET_REPLACE IP6T_SO_SET_REPLACE
99 #define SO_SET_ADD_COUNTERS IP6T_SO_SET_ADD_COUNTERS
100 #define SO_GET_INFO IP6T_SO_GET_INFO
101 #define SO_GET_ENTRIES IP6T_SO_GET_ENTRIES
102 #define SO_GET_VERSION IP6T_SO_GET_VERSION
104 #define STANDARD_TARGET IP6T_STANDARD_TARGET
105 #define LABEL_RETURN IP6TC_LABEL_RETURN
106 #define LABEL_ACCEPT IP6TC_LABEL_ACCEPT
107 #define LABEL_DROP IP6TC_LABEL_DROP
108 #define LABEL_QUEUE IP6TC_LABEL_QUEUE
110 #define ALIGN IP6T_ALIGN
111 #define RETURN IP6T_RETURN
116 ((ntohl(a->in6_u.u6_addr32[(l) / 32]) >> (31 - ((l) & 31))) & 1)
119 ipv6_prefix_length(const struct in6_addr
*a
)
122 for (l
= 0; l
< 128; l
++) {
126 for (i
= l
+ 1; i
< 128; i
++) {
135 dump_entry(struct ip6t_entry
*e
, const ip6tc_handle_t handle
)
140 struct ip6t_entry_target
*t
;
142 printf("Entry %u (%lu):\n", iptcb_entry2index(handle
, e
),
143 iptcb_entry2offset(handle
, e
));
145 inet_ntop(AF_INET6
, &e
->ipv6
.src
, buf
, sizeof buf
);
148 len
= ipv6_prefix_length(&e
->ipv6
.smsk
);
152 inet_ntop(AF_INET6
, &e
->ipv6
.smsk
, buf
, sizeof buf
);
158 inet_ntop(AF_INET6
, &e
->ipv6
.dst
, buf
, sizeof buf
);
161 len
= ipv6_prefix_length(&e
->ipv6
.dmsk
);
165 inet_ntop(AF_INET6
, &e
->ipv6
.dmsk
, buf
, sizeof buf
);
170 printf("Interface: `%s'/", e
->ipv6
.iniface
);
171 for (i
= 0; i
< IFNAMSIZ
; i
++)
172 printf("%c", e
->ipv6
.iniface_mask
[i
] ? 'X' : '.');
173 printf("to `%s'/", e
->ipv6
.outiface
);
174 for (i
= 0; i
< IFNAMSIZ
; i
++)
175 printf("%c", e
->ipv6
.outiface_mask
[i
] ? 'X' : '.');
176 printf("\nProtocol: %u\n", e
->ipv6
.proto
);
177 if (e
->ipv6
.flags
& IP6T_F_TOS
)
178 printf("TOS: %u\n", e
->ipv6
.tos
);
179 printf("Flags: %02X\n", e
->ipv6
.flags
);
180 printf("Invflags: %02X\n", e
->ipv6
.invflags
);
181 printf("Counters: %llu packets, %llu bytes\n",
182 (unsigned long long)e
->counters
.pcnt
, (unsigned long long)e
->counters
.bcnt
);
183 printf("Cache: %08X ", e
->nfcache
);
184 if (e
->nfcache
& NFC_ALTERED
) printf("ALTERED ");
185 if (e
->nfcache
& NFC_UNKNOWN
) printf("UNKNOWN ");
188 IP6T_MATCH_ITERATE(e
, print_match
);
190 t
= ip6t_get_target(e
);
191 printf("Target name: `%s' [%u]\n", t
->u
.user
.name
, t
->u
.target_size
);
192 if (strcmp(t
->u
.user
.name
, IP6T_STANDARD_TARGET
) == 0) {
193 int pos
= *(int *)t
->data
;
195 printf("verdict=%s\n",
196 pos
== -NF_ACCEPT
-1 ? "NF_ACCEPT"
197 : pos
== -NF_DROP
-1 ? "NF_DROP"
198 : pos
== IP6T_RETURN
? "RETURN"
201 printf("verdict=%u\n", pos
);
202 } else if (strcmp(t
->u
.user
.name
, IP6T_ERROR_TARGET
) == 0)
203 printf("error=`%s'\n", t
->data
);
210 static unsigned char *
211 is_same(const STRUCT_ENTRY
*a
, const STRUCT_ENTRY
*b
,
212 unsigned char *matchmask
)
217 /* Always compare head structures: ignore mask here. */
218 if (memcmp(&a
->ipv6
.src
, &b
->ipv6
.src
, sizeof(struct in6_addr
))
219 || memcmp(&a
->ipv6
.dst
, &b
->ipv6
.dst
, sizeof(struct in6_addr
))
220 || memcmp(&a
->ipv6
.smsk
, &b
->ipv6
.smsk
, sizeof(struct in6_addr
))
221 || memcmp(&a
->ipv6
.dmsk
, &b
->ipv6
.dmsk
, sizeof(struct in6_addr
))
222 || a
->ipv6
.proto
!= b
->ipv6
.proto
223 || a
->ipv6
.tos
!= b
->ipv6
.tos
224 || a
->ipv6
.flags
!= b
->ipv6
.flags
225 || a
->ipv6
.invflags
!= b
->ipv6
.invflags
)
228 for (i
= 0; i
< IFNAMSIZ
; i
++) {
229 if (a
->ipv6
.iniface_mask
[i
] != b
->ipv6
.iniface_mask
[i
])
231 if ((a
->ipv6
.iniface
[i
] & a
->ipv6
.iniface_mask
[i
])
232 != (b
->ipv6
.iniface
[i
] & b
->ipv6
.iniface_mask
[i
]))
234 if (a
->ipv6
.outiface_mask
[i
] != b
->ipv6
.outiface_mask
[i
])
236 if ((a
->ipv6
.outiface
[i
] & a
->ipv6
.outiface_mask
[i
])
237 != (b
->ipv6
.outiface
[i
] & b
->ipv6
.outiface_mask
[i
]))
241 if (a
->nfcache
!= b
->nfcache
242 || a
->target_offset
!= b
->target_offset
243 || a
->next_offset
!= b
->next_offset
)
246 mptr
= matchmask
+ sizeof(STRUCT_ENTRY
);
247 if (IP6T_MATCH_ITERATE(a
, match_different
, a
->elems
, b
->elems
, &mptr
))
249 mptr
+= IP6T_ALIGN(sizeof(struct ip6t_entry_target
));
254 /* All zeroes == unconditional rule. */
256 unconditional(const struct ip6t_ip6
*ipv6
)
260 for (i
= 0; i
< sizeof(*ipv6
); i
++)
261 if (((char *)ipv6
)[i
])
264 return (i
== sizeof(*ipv6
));
268 /* Do every conceivable sanity check on the handle */
270 do_check(TC_HANDLE_T h
, unsigned int line
)
273 unsigned int user_offset
; /* Offset of first user chain */
276 assert(h
->changed
== 0 || h
->changed
== 1);
277 if (strcmp(h
->info
.name
, "filter") == 0) {
278 assert(h
->info
.valid_hooks
279 == (1 << NF_IP6_LOCAL_IN
280 | 1 << NF_IP6_FORWARD
281 | 1 << NF_IP6_LOCAL_OUT
));
283 /* Hooks should be first three */
284 assert(h
->info
.hook_entry
[NF_IP6_LOCAL_IN
] == 0);
286 n
= get_chain_end(h
, 0);
287 n
+= get_entry(h
, n
)->next_offset
;
288 assert(h
->info
.hook_entry
[NF_IP6_FORWARD
] == n
);
290 n
= get_chain_end(h
, n
);
291 n
+= get_entry(h
, n
)->next_offset
;
292 assert(h
->info
.hook_entry
[NF_IP6_LOCAL_OUT
] == n
);
294 user_offset
= h
->info
.hook_entry
[NF_IP6_LOCAL_OUT
];
295 } else if (strcmp(h
->info
.name
, "nat") == 0) {
296 assert((h
->info
.valid_hooks
297 == (1 << NF_IP6_PRE_ROUTING
298 | 1 << NF_IP6_LOCAL_OUT
299 | 1 << NF_IP6_POST_ROUTING
)) ||
301 == (1 << NF_IP6_PRE_ROUTING
302 | 1 << NF_IP6_LOCAL_IN
303 | 1 << NF_IP6_LOCAL_OUT
304 | 1 << NF_IP6_POST_ROUTING
)));
306 assert(h
->info
.hook_entry
[NF_IP6_PRE_ROUTING
] == 0);
308 n
= get_chain_end(h
, 0);
310 n
+= get_entry(h
, n
)->next_offset
;
311 assert(h
->info
.hook_entry
[NF_IP6_POST_ROUTING
] == n
);
312 n
= get_chain_end(h
, n
);
314 n
+= get_entry(h
, n
)->next_offset
;
315 assert(h
->info
.hook_entry
[NF_IP6_LOCAL_OUT
] == n
);
316 user_offset
= h
->info
.hook_entry
[NF_IP6_LOCAL_OUT
];
318 if (h
->info
.valid_hooks
& (1 << NF_IP6_LOCAL_IN
)) {
319 n
= get_chain_end(h
, n
);
320 n
+= get_entry(h
, n
)->next_offset
;
321 assert(h
->info
.hook_entry
[NF_IP6_LOCAL_IN
] == n
);
322 user_offset
= h
->info
.hook_entry
[NF_IP6_LOCAL_IN
];
325 } else if (strcmp(h
->info
.name
, "mangle") == 0) {
326 /* This code is getting ugly because linux < 2.4.18-pre6 had
327 * two mangle hooks, linux >= 2.4.18-pre6 has five mangle hooks
329 assert((h
->info
.valid_hooks
330 == (1 << NF_IP6_PRE_ROUTING
331 | 1 << NF_IP6_LOCAL_OUT
)) ||
333 == (1 << NF_IP6_PRE_ROUTING
334 | 1 << NF_IP6_LOCAL_IN
335 | 1 << NF_IP6_FORWARD
336 | 1 << NF_IP6_LOCAL_OUT
337 | 1 << NF_IP6_POST_ROUTING
)));
339 /* Hooks should be first five */
340 assert(h
->info
.hook_entry
[NF_IP6_PRE_ROUTING
] == 0);
342 n
= get_chain_end(h
, 0);
344 if (h
->info
.valid_hooks
& (1 << NF_IP6_LOCAL_IN
)) {
345 n
+= get_entry(h
, n
)->next_offset
;
346 assert(h
->info
.hook_entry
[NF_IP6_LOCAL_IN
] == n
);
347 n
= get_chain_end(h
, n
);
350 if (h
->info
.valid_hooks
& (1 << NF_IP6_FORWARD
)) {
351 n
+= get_entry(h
, n
)->next_offset
;
352 assert(h
->info
.hook_entry
[NF_IP6_FORWARD
] == n
);
353 n
= get_chain_end(h
, n
);
356 n
+= get_entry(h
, n
)->next_offset
;
357 assert(h
->info
.hook_entry
[NF_IP6_LOCAL_OUT
] == n
);
358 user_offset
= h
->info
.hook_entry
[NF_IP6_LOCAL_OUT
];
360 if (h
->info
.valid_hooks
& (1 << NF_IP6_POST_ROUTING
)) {
361 n
= get_chain_end(h
, n
);
362 n
+= get_entry(h
, n
)->next_offset
;
363 assert(h
->info
.hook_entry
[NF_IP6_POST_ROUTING
] == n
);
364 user_offset
= h
->info
.hook_entry
[NF_IP6_POST_ROUTING
];
366 } else if (strcmp(h
->info
.name
, "raw") == 0) {
367 assert(h
->info
.valid_hooks
368 == (1 << NF_IP6_PRE_ROUTING
369 | 1 << NF_IP6_LOCAL_OUT
));
371 /* Hooks should be first three */
372 assert(h
->info
.hook_entry
[NF_IP6_PRE_ROUTING
] == 0);
374 n
= get_chain_end(h
, n
);
375 n
+= get_entry(h
, n
)->next_offset
;
376 assert(h
->info
.hook_entry
[NF_IP6_LOCAL_OUT
] == n
);
378 user_offset
= h
->info
.hook_entry
[NF_IP6_LOCAL_OUT
];
380 fprintf(stderr
, "Unknown table `%s'\n", h
->info
.name
);
384 /* User chain == end of last builtin + policy entry */
385 user_offset
= get_chain_end(h
, user_offset
);
386 user_offset
+= get_entry(h
, user_offset
)->next_offset
;
388 /* Overflows should be end of entry chains, and unconditional
390 for (i
= 0; i
< NUMHOOKS
; i
++) {
392 STRUCT_STANDARD_TARGET
*t
;
394 if (!(h
->info
.valid_hooks
& (1 << i
)))
396 assert(h
->info
.underflow
[i
]
397 == get_chain_end(h
, h
->info
.hook_entry
[i
]));
399 e
= get_entry(h
, get_chain_end(h
, h
->info
.hook_entry
[i
]));
400 assert(unconditional(&e
->ipv6
));
401 assert(e
->target_offset
== sizeof(*e
));
402 t
= (STRUCT_STANDARD_TARGET
*)GET_TARGET(e
);
403 printf("target_size=%u, align=%u\n",
404 t
->target
.u
.target_size
, ALIGN(sizeof(*t
)));
405 assert(t
->target
.u
.target_size
== ALIGN(sizeof(*t
)));
406 assert(e
->next_offset
== sizeof(*e
) + ALIGN(sizeof(*t
)));
408 assert(strcmp(t
->target
.u
.user
.name
, STANDARD_TARGET
)==0);
409 assert(t
->verdict
== -NF_DROP
-1 || t
->verdict
== -NF_ACCEPT
-1);
411 /* Hooks and underflows must be valid entries */
412 iptcb_entry2index(h
, get_entry(h
, h
->info
.hook_entry
[i
]));
413 iptcb_entry2index(h
, get_entry(h
, h
->info
.underflow
[i
]));
417 >= h
->info
.num_entries
* (sizeof(STRUCT_ENTRY
)
418 +sizeof(STRUCT_STANDARD_TARGET
)));
420 assert(h
->entries
.size
422 * (sizeof(STRUCT_ENTRY
)
423 + sizeof(STRUCT_STANDARD_TARGET
))));
424 assert(strcmp(h
->info
.name
, h
->entries
.name
) == 0);
430 /* Check all the entries. */
431 ENTRY_ITERATE(h
->entries
.entrytable
, h
->entries
.size
,
432 check_entry
, &i
, &n
, user_offset
, &was_return
, h
);
434 assert(i
== h
->new_number
);
435 assert(n
== h
->entries
.size
);
437 /* Final entry must be error node */
438 assert(strcmp(GET_TARGET(index2entry(h
, h
->new_number
-1))
443 #endif /*IPTC_DEBUG*/