libip6tc.c revision 79dee0702b18c8ea1d1f7a2b1f6b29349466986b
1/* Library which manipulates firewall rules. Version 0.1. */ 2 3/* Architecture of firewall rules is as follows: 4 * 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. 9 */ 10 11/* (C)1999 Paul ``Rusty'' Russell - Placed under the GNU GPL (See 12 COPYING for details). */ 13 14#include <assert.h> 15#include <string.h> 16#include <errno.h> 17#include <stdlib.h> 18#include <stdio.h> 19#include <arpa/inet.h> 20 21#ifdef DEBUG_CONNTRACK 22#define inline 23#endif 24 25#if !defined(__GLIBC__) || (__GLIBC__ < 2) 26typedef unsigned int socklen_t; 27#endif 28 29#include "libiptc/libip6tc.h" 30 31#define HOOK_PRE_ROUTING NF_IP6_PRE_ROUTING 32#define HOOK_LOCAL_IN NF_IP6_LOCAL_IN 33#define HOOK_FORWARD NF_IP6_FORWARD 34#define HOOK_LOCAL_OUT NF_IP6_LOCAL_OUT 35#define HOOK_POST_ROUTING NF_IP6_POST_ROUTING 36 37#define STRUCT_ENTRY_TARGET struct ip6t_entry_target 38#define STRUCT_ENTRY struct ip6t_entry 39#define STRUCT_ENTRY_MATCH struct ip6t_entry_match 40#define STRUCT_GETINFO struct ip6t_getinfo 41#define STRUCT_GET_ENTRIES struct ip6t_get_entries 42#define STRUCT_COUNTERS struct ip6t_counters 43#define STRUCT_COUNTERS_INFO struct ip6t_counters_info 44#define STRUCT_STANDARD_TARGET struct ip6t_standard_target 45#define STRUCT_REPLACE struct ip6t_replace 46 47#define STRUCT_TC_HANDLE struct ip6tc_handle 48#define TC_HANDLE_T ip6tc_handle_t 49 50#define ENTRY_ITERATE IP6T_ENTRY_ITERATE 51#define TABLE_MAXNAMELEN IP6T_TABLE_MAXNAMELEN 52#define FUNCTION_MAXNAMELEN IP6T_FUNCTION_MAXNAMELEN 53 54#define GET_TARGET ip6t_get_target 55 56#define ERROR_TARGET IP6T_ERROR_TARGET 57#define NUMHOOKS NF_IP6_NUMHOOKS 58 59#define IPT_CHAINLABEL ip6t_chainlabel 60 61#define TC_DUMP_ENTRIES dump_entries6 62#define TC_IS_CHAIN ip6tc_is_chain 63#define TC_NEXT_CHAIN ip6tc_next_chain 64#define TC_NUM_RULES ip6tc_num_rules 65#define TC_GET_RULE ip6tc_get_rule 66#define TC_GET_TARGET ip6tc_get_target 67#define TC_BUILTIN ip6tc_builtin 68#define TC_GET_POLICY ip6tc_get_policy 69#define TC_INSERT_ENTRY ip6tc_insert_entry 70#define TC_REPLACE_ENTRY ip6tc_replace_entry 71#define TC_APPEND_ENTRY ip6tc_append_entry 72#define TC_DELETE_ENTRY ip6tc_delete_entry 73#define TC_DELETE_NUM_ENTRY ip6tc_delete_num_entry 74#define TC_CHECK_PACKET ip6tc_check_packet 75#define TC_FLUSH_ENTRIES ip6tc_flush_entries 76#define TC_ZERO_ENTRIES ip6tc_zero_entries 77#define TC_CREATE_CHAIN ip6tc_create_chain 78#define TC_GET_REFERENCES ip6tc_get_references 79#define TC_DELETE_CHAIN ip6tc_delete_chain 80#define TC_RENAME_CHAIN ip6tc_rename_chain 81#define TC_SET_POLICY ip6tc_set_policy 82#define TC_GET_RAW_SOCKET ip6tc_get_raw_socket 83#define TC_INIT ip6tc_init 84#define TC_COMMIT ip6tc_commit 85#define TC_STRERROR ip6tc_strerror 86 87#define TC_AF AF_INET6 88#define TC_IPPROTO IPPROTO_IPV6 89 90#define SO_SET_REPLACE IP6T_SO_SET_REPLACE 91#define SO_SET_ADD_COUNTERS IP6T_SO_SET_ADD_COUNTERS 92#define SO_GET_INFO IP6T_SO_GET_INFO 93#define SO_GET_ENTRIES IP6T_SO_GET_ENTRIES 94#define SO_GET_VERSION IP6T_SO_GET_VERSION 95 96#define STANDARD_TARGET IP6T_STANDARD_TARGET 97#define LABEL_RETURN IP6TC_LABEL_RETURN 98#define LABEL_ACCEPT IP6TC_LABEL_ACCEPT 99#define LABEL_DROP IP6TC_LABEL_DROP 100 101#define ALIGN IP6T_ALIGN 102#define RETURN IP6T_RETURN 103 104#include "libiptc.c" 105 106#define BIT6(a, l) \ 107 (((a->in6_u.u6_addr32[(l) / 32]) >> ((l) & 31)) & 1) 108 109int 110ipv6_prefix_length(const struct in6_addr *a) 111{ 112 int l, i; 113 for (l = 0; l < 128; l++) { 114 if (BIT6(a, l) == 0) 115 break; 116 } 117 for (i = l + 1; i < 128; i++) { 118 if (BIT6(a, i) == 1) 119 return -1; 120 } 121 return l; 122} 123 124static int 125dump_entry(struct ip6t_entry *e, const ip6tc_handle_t handle) 126{ 127 size_t i; 128 char buf[40]; 129 int len; 130 struct ip6t_entry_target *t; 131 132 printf("Entry %u (%lu):\n", entry2index(handle, e), 133 entry2offset(handle, e)); 134 puts("SRC IP: "); 135 inet_ntop(AF_INET6, &e->ipv6.src, buf, sizeof buf); 136 puts(buf); 137 putchar('/'); 138 len = ipv6_prefix_length(&e->ipv6.smsk); 139 if (len != -1) 140 printf("%d", len); 141 else { 142 inet_ntop(AF_INET6, &e->ipv6.smsk, buf, sizeof buf); 143 puts(buf); 144 } 145 putchar('\n'); 146 147 puts("DST IP: "); 148 inet_ntop(AF_INET6, &e->ipv6.dst, buf, sizeof buf); 149 puts(buf); 150 putchar('/'); 151 len = ipv6_prefix_length(&e->ipv6.dmsk); 152 if (len != -1) 153 printf("%d", len); 154 else { 155 inet_ntop(AF_INET6, &e->ipv6.dmsk, buf, sizeof buf); 156 puts(buf); 157 } 158 putchar('\n'); 159 160 printf("Interface: `%s'/", e->ipv6.iniface); 161 for (i = 0; i < IFNAMSIZ; i++) 162 printf("%c", e->ipv6.iniface_mask[i] ? 'X' : '.'); 163 printf("to `%s'/", e->ipv6.outiface); 164 for (i = 0; i < IFNAMSIZ; i++) 165 printf("%c", e->ipv6.outiface_mask[i] ? 'X' : '.'); 166 printf("\nProtocol: %u\n", e->ipv6.proto); 167 if (e->ipv6.flags & IP6T_F_TOS) 168 printf("TOS: %u\n", e->ipv6.tos); 169 printf("Flags: %02X\n", e->ipv6.flags); 170 printf("Invflags: %02X\n", e->ipv6.invflags); 171 printf("Counters: %llu packets, %llu bytes\n", 172 e->counters.pcnt, e->counters.bcnt); 173 printf("Cache: %08X ", e->nfcache); 174 if (e->nfcache & NFC_ALTERED) printf("ALTERED "); 175 if (e->nfcache & NFC_UNKNOWN) printf("UNKNOWN "); 176 if (e->nfcache & NFC_IP6_SRC) printf("IP6_SRC "); 177 if (e->nfcache & NFC_IP6_DST) printf("IP6_DST "); 178 if (e->nfcache & NFC_IP6_IF_IN) printf("IP6_IF_IN "); 179 if (e->nfcache & NFC_IP6_IF_OUT) printf("IP6_IF_OUT "); 180 if (e->nfcache & NFC_IP6_TOS) printf("IP6_TOS "); 181 if (e->nfcache & NFC_IP6_PROTO) printf("IP6_PROTO "); 182 if (e->nfcache & NFC_IP6_OPTIONS) printf("IP6_OPTIONS "); 183 if (e->nfcache & NFC_IP6_TCPFLAGS) printf("IP6_TCPFLAGS "); 184 if (e->nfcache & NFC_IP6_SRC_PT) printf("IP6_SRC_PT "); 185 if (e->nfcache & NFC_IP6_DST_PT) printf("IP6_DST_PT "); 186 if (e->nfcache & NFC_IP6_PROTO_UNKNOWN) printf("IP6_PROTO_UNKNOWN "); 187 printf("\n"); 188 189 IP6T_MATCH_ITERATE(e, print_match); 190 191 t = ip6t_get_target(e); 192 printf("Target name: `%s' [%u]\n", t->u.name, t->target_size); 193 if (strcmp(t->u.name, IP6T_STANDARD_TARGET) == 0) { 194 int pos = *(int *)t->data; 195 if (pos < 0) 196 printf("verdict=%s\n", 197 pos == -NF_ACCEPT-1 ? "NF_ACCEPT" 198 : pos == -NF_DROP-1 ? "NF_DROP" 199 : pos == IP6T_RETURN ? "RETURN" 200 : "UNKNOWN"); 201 else 202 printf("verdict=%u\n", pos); 203 } else if (strcmp(t->u.name, IP6T_ERROR_TARGET) == 0) 204 printf("error=`%s'\n", t->data); 205 206 printf("\n"); 207 return 0; 208} 209 210static inline int 211is_same(const struct STRUCT_ENTRY *a, const struct STRUCT_ENTRY *b, 212 unsigned char *matchmask) 213{ 214 unsigned int i; 215 struct STRUCT_ENTRY_TARGET *ta, *tb; 216 unsigned char *mptr; 217 218 /* Always compare head structures: ignore mask here. */ 219 if (memcmp(&a->ipv6.src, &b->ipv6.src, sizeof(struct in6_addr)) 220 || memcmp(&a->ipv6.dst, &b->ipv6.dst, sizeof(struct in6_addr)) 221 || memcmp(&a->ipv6.smsk, &b->ipv6.smsk, sizeof(struct in6_addr)) 222 || memcmp(&a->ipv6.dmsk, &b->ipv6.dmsk, sizeof(struct in6_addr)) 223 || a->ipv6.proto != b->ipv6.proto 224 || a->ipv6.tos != b->ipv6.tos 225 || a->ipv6.flags != b->ipv6.flags 226 || a->ipv6.invflags != b->ipv6.invflags) 227 return 0; 228 229 for (i = 0; i < IFNAMSIZ; i++) { 230 if (a->ipv6.iniface_mask[i] != b->ipv6.iniface_mask[i]) 231 return 0; 232 if ((a->ipv6.iniface[i] & a->ipv6.iniface_mask[i]) 233 != (b->ipv6.iniface[i] & b->ipv6.iniface_mask[i])) 234 return 0; 235 if (a->ipv6.outiface_mask[i] != b->ipv6.outiface_mask[i]) 236 return 0; 237 if ((a->ipv6.outiface[i] & a->ipv6.outiface_mask[i]) 238 != (b->ipv6.outiface[i] & b->ipv6.outiface_mask[i])) 239 return 0; 240 } 241 242 if (a->nfcache != b->nfcache 243 || a->target_offset != b->target_offset 244 || a->next_offset != b->next_offset) 245 return 0; 246 247 mptr = matchmask + sizeof(struct STRUCT_ENTRY); 248 if (IP6T_MATCH_ITERATE(a, match_different, a->elems, b->elems)) 249 return 0; 250 251 ta = GET_TARGET((struct STRUCT_ENTRY *)a); 252 tb = GET_TARGET((struct STRUCT_ENTRY *)b); 253 if (ta->target_size != tb->target_size) 254 return 0; 255 if (strcmp(ta->u.name, tb->u.name) != 0) 256 return 0; 257 mptr += sizeof(*ta); 258 259 if (target_different(ta->data, tb->data, 260 ta->u.target_size - sizeof(*ta), mptr)) 261 return 0; 262 263 return 1; 264} 265