Free (GPLv2) TCP/IP stack developed by TASS Belgium
Dependents: lpc1768-picotcp-demo ZeroMQ_PicoTCP_Publisher_demo TCPSocket_HelloWorld_PicoTCP Pico_TCP_UDP_Test ... more
pico_ipfilter.c
00001 /********************************************************************* 00002 PicoTCP. Copyright (c) 2012-2015 Altran Intelligent Systems. Some rights reserved. 00003 See LICENSE and COPYING for usage. 00004 00005 Authors: Andrei Carp 00006 Simon Maes 00007 *********************************************************************/ 00008 00009 #include "pico_ipv4.h" 00010 #include "pico_config.h" 00011 #include "pico_icmp4.h" 00012 #include "pico_stack.h" 00013 #include "pico_eth.h" 00014 #include "pico_socket.h" 00015 #include "pico_device.h" 00016 #include "pico_ipfilter.h" 00017 #include "pico_tcp.h" 00018 #include "pico_udp.h" 00019 #include "pico_tree.h" 00020 00021 /**************** LOCAL MACROS ****************/ 00022 #define MAX_PRIORITY (10) 00023 #define MIN_PRIORITY (-10) 00024 00025 #define ipf_dbg(...) do {} while(0) 00026 00027 /**************** LOCAL DECLARATIONS ****************/ 00028 struct filter_node; 00029 static int filter_compare(void *filterA, void *filterB); 00030 00031 /**************** FILTER TREE ****************/ 00032 00033 struct filter_node { 00034 struct pico_device *fdev; 00035 /* output address */ 00036 uint32_t out_addr; 00037 uint32_t out_addr_netmask; 00038 /* input address */ 00039 uint32_t in_addr; 00040 uint32_t in_addr_netmask; 00041 /* transport */ 00042 uint16_t out_port; 00043 uint16_t in_port; 00044 /* filter details */ 00045 uint8_t proto; 00046 int8_t priority; 00047 uint8_t tos; 00048 uint32_t filter_id; 00049 int (*function_ptr)(struct filter_node *filter, struct pico_frame *f); 00050 }; 00051 00052 PICO_TREE_DECLARE(filter_tree, &filter_compare); 00053 00054 static inline int ipfilter_uint32_cmp(uint32_t a, uint32_t b) 00055 { 00056 if (a < b) 00057 return -1; 00058 00059 if (b < a) 00060 return 1; 00061 00062 return 0; 00063 } 00064 00065 static inline int ipfilter_uint16_cmp(uint16_t a, uint16_t b) 00066 { 00067 if (a < b) 00068 return -1; 00069 00070 if (b < a) 00071 return 1; 00072 00073 return 0; 00074 } 00075 00076 static inline int ipfilter_uint8_cmp(uint8_t a, uint8_t b) 00077 { 00078 if (a < b) 00079 return -1; 00080 00081 if (b < a) 00082 return 1; 00083 00084 return 0; 00085 } 00086 00087 static inline int ipfilter_ptr_cmp(void *a, void *b) 00088 { 00089 if (a < b) 00090 return -1; 00091 00092 if (b < a) 00093 return 1; 00094 00095 return 0; 00096 } 00097 00098 00099 00100 static inline int filter_compare_ports(struct filter_node *a, struct filter_node *b) 00101 { 00102 int cmp; 00103 cmp = ipfilter_uint16_cmp(a->in_port, b->in_port); 00104 if (cmp) 00105 return cmp; 00106 00107 cmp = ipfilter_uint16_cmp(a->out_port, b->out_port); 00108 return cmp; 00109 } 00110 00111 static inline int filter_compare_addresses(struct filter_node *a, struct filter_node *b) 00112 { 00113 int cmp; 00114 /* Compare source address */ 00115 cmp = ipfilter_uint32_cmp((a->in_addr & a->in_addr_netmask), (b->in_addr & b->in_addr_netmask)); 00116 if (cmp) 00117 return cmp; 00118 00119 /* Compare destination address */ 00120 cmp = ipfilter_uint32_cmp((a->out_addr & a->out_addr_netmask), (b->out_addr & b->out_addr_netmask)); 00121 return cmp; 00122 } 00123 00124 static inline int filter_compare_proto(struct filter_node *a, struct filter_node *b) 00125 { 00126 return ipfilter_uint8_cmp(a->proto, b->proto); 00127 } 00128 00129 static inline int filter_compare_address_port(struct filter_node *a, struct filter_node *b) 00130 { 00131 int cmp; 00132 cmp = filter_compare_addresses(a, b); 00133 if (cmp) 00134 return cmp; 00135 00136 return filter_compare_ports(a, b); 00137 } 00138 00139 static inline int filter_match_packet_dev(struct filter_node *a, struct filter_node *b, struct filter_node *rule) 00140 { 00141 int cmp; 00142 /* 1. Compare devices */ 00143 if (rule->fdev) { 00144 cmp = ipfilter_ptr_cmp(a->fdev, b->fdev); 00145 if (cmp) 00146 return cmp; 00147 } 00148 00149 return 0; 00150 00151 } 00152 00153 static inline int filter_match_packet_proto(struct filter_node *a, struct filter_node *b, struct filter_node *rule) 00154 { 00155 int cmp; 00156 /* 2. Compare protocol */ 00157 if (rule->proto) { 00158 cmp = filter_compare_proto(a, b); 00159 if (cmp) 00160 return cmp; 00161 } 00162 00163 return 0; 00164 00165 } 00166 static inline int filter_match_packet_addr_in(struct filter_node *a, struct filter_node *b, struct filter_node *rule) 00167 { 00168 int cmp; 00169 /* 3. Compare addresses order: in, out */ 00170 if (rule->in_addr_netmask) { 00171 cmp = ipfilter_uint32_cmp(a->in_addr & rule->in_addr_netmask, b->in_addr & rule->in_addr_netmask); 00172 if (cmp) 00173 return cmp; 00174 } 00175 00176 return 0; 00177 } 00178 static inline int filter_match_packet_addr_out(struct filter_node *a, struct filter_node *b, struct filter_node *rule) 00179 { 00180 int cmp; 00181 if (rule->out_addr_netmask) { 00182 cmp = ipfilter_uint32_cmp(a->out_addr & rule->out_addr_netmask, b->out_addr & rule->out_addr_netmask); 00183 if (cmp) { 00184 return cmp; 00185 } 00186 } 00187 00188 return 0; 00189 } 00190 static inline int filter_match_packet_port_in(struct filter_node *a, struct filter_node *b, struct filter_node *rule) 00191 { 00192 int cmp; 00193 /* 4. Compare ports order: in, out */ 00194 if (rule->in_port) { 00195 cmp = ipfilter_uint16_cmp(a->in_port, b->in_port); 00196 if (cmp) 00197 return cmp; 00198 } 00199 00200 return 0; 00201 } 00202 static inline int filter_match_packet_port_out(struct filter_node *a, struct filter_node *b, struct filter_node *rule) 00203 { 00204 int cmp; 00205 if (rule->out_port) { 00206 cmp = ipfilter_uint16_cmp(a->out_port, b->out_port); 00207 if (cmp) 00208 return cmp; 00209 } 00210 00211 return 0; 00212 } 00213 00214 static inline int filter_match_packet_dev_and_proto(struct filter_node *a, struct filter_node *b, struct filter_node *rule) 00215 { 00216 int cmp = filter_match_packet_dev(a, b, rule); 00217 if (cmp) 00218 return cmp; 00219 00220 return filter_match_packet_proto(a, b, rule); 00221 } 00222 00223 static inline int filter_match_packet_addr(struct filter_node *a, struct filter_node *b, struct filter_node *rule) 00224 { 00225 int cmp = filter_match_packet_addr_in(a, b, rule); 00226 if (cmp) 00227 return cmp; 00228 00229 return filter_match_packet_addr_out(a, b, rule); 00230 00231 } 00232 00233 static inline int filter_match_packet_port(struct filter_node *a, struct filter_node *b, struct filter_node *rule) 00234 { 00235 int cmp = filter_match_packet_port_in(a, b, rule); 00236 if (cmp) 00237 return cmp; 00238 00239 return filter_match_packet_port_out(a, b, rule); 00240 } 00241 00242 static inline struct filter_node *filter_match_packet_find_rule(struct filter_node *a, struct filter_node *b) 00243 { 00244 if (!a->filter_id) 00245 return b; 00246 00247 return a; 00248 } 00249 00250 static inline int filter_match_packet(struct filter_node *a, struct filter_node *b) 00251 { 00252 struct filter_node *rule; 00253 int cmp = 0; 00254 rule = filter_match_packet_find_rule(a, b); 00255 00256 cmp = filter_match_packet_dev_and_proto(a, b, rule); 00257 if (cmp) 00258 return cmp; 00259 00260 cmp = filter_match_packet_addr(a, b, rule); 00261 if (cmp) 00262 return cmp; 00263 00264 cmp = filter_match_packet_port(a, b, rule); 00265 if (cmp) 00266 return cmp; 00267 00268 return 0; 00269 } 00270 00271 00272 int filter_compare(void *filterA, void *filterB) 00273 { 00274 00275 struct filter_node *a = (struct filter_node *)filterA; 00276 struct filter_node *b = (struct filter_node *)filterB; 00277 int cmp = 0; 00278 if (a->filter_id == 0 || b->filter_id == 0) { 00279 return filter_match_packet(a, b); 00280 } 00281 00282 /* improve the search */ 00283 if(a->filter_id == b->filter_id) 00284 return 0; 00285 00286 /* 1. Compare devices */ 00287 cmp = ipfilter_ptr_cmp(a->fdev, a->fdev); 00288 if (cmp) 00289 return cmp; 00290 00291 /* 2. Compare protocol */ 00292 cmp = filter_compare_proto(a, b); 00293 if(cmp) 00294 return cmp; 00295 00296 /* 3. Compare addresses order: in, out */ 00297 /* 4. Compare ports order: in, out */ 00298 cmp = filter_compare_address_port(a, b); 00299 00300 return cmp; 00301 } 00302 00303 /**************** FILTER CALLBACKS ****************/ 00304 00305 static int fp_priority(struct filter_node *filter, struct pico_frame *f) 00306 { 00307 /* TODO do priority-stuff */ 00308 IGNORE_PARAMETER(filter); 00309 IGNORE_PARAMETER(f); 00310 return 0; 00311 } 00312 00313 static int fp_reject(struct filter_node *filter, struct pico_frame *f) 00314 { 00315 /* TODO check first if sender is pico itself or not */ 00316 IGNORE_PARAMETER(filter); 00317 ipf_dbg("ipfilter> reject\n"); 00318 (void)pico_icmp4_packet_filtered(f); 00319 pico_frame_discard(f); 00320 return 1; 00321 } 00322 00323 static int fp_drop(struct filter_node *filter, struct pico_frame *f) 00324 { 00325 IGNORE_PARAMETER(filter); 00326 ipf_dbg("ipfilter> drop\n"); 00327 pico_frame_discard(f); 00328 return 1; 00329 } 00330 00331 struct fp_function { 00332 int (*fn)(struct filter_node *filter, struct pico_frame *f); 00333 }; 00334 00335 00336 static const struct fp_function fp_function[FILTER_COUNT] = 00337 { 00338 {&fp_priority}, 00339 {&fp_reject}, 00340 {&fp_drop} 00341 }; 00342 00343 static int pico_ipv4_filter_add_validate(int8_t priority, enum filter_action action) 00344 { 00345 if ( priority > MAX_PRIORITY || priority < MIN_PRIORITY) { 00346 return -1; 00347 } 00348 00349 if (action >= FILTER_COUNT) { 00350 return -1; 00351 } 00352 00353 return 0; 00354 } 00355 00356 00357 /**************** FILTER API's ****************/ 00358 uint32_t pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto, 00359 struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask, 00360 struct pico_ip4 *in_addr, struct pico_ip4 *in_addr_netmask, 00361 uint16_t out_port, uint16_t in_port, int8_t priority, 00362 uint8_t tos, enum filter_action action) 00363 { 00364 static uint32_t filter_id = 1u; /* 0 is a special value used in the binary-tree search for packets being processed */ 00365 struct filter_node *new_filter; 00366 00367 if (pico_ipv4_filter_add_validate(priority, action) < 0) { 00368 pico_err = PICO_ERR_EINVAL; 00369 return 0; 00370 } 00371 00372 new_filter = PICO_ZALLOC(sizeof(struct filter_node)); 00373 if (!new_filter) { 00374 pico_err = PICO_ERR_ENOMEM; 00375 return 0; 00376 } 00377 00378 new_filter->fdev = dev; 00379 new_filter->proto = proto; 00380 new_filter->out_addr = (!out_addr) ? (0U) : (out_addr->addr); 00381 new_filter->out_addr_netmask = (!out_addr_netmask) ? (0U) : (out_addr_netmask->addr); 00382 new_filter->in_addr = (!in_addr) ? (0U) : (in_addr->addr); 00383 new_filter->in_addr_netmask = (!in_addr_netmask) ? (0U) : (in_addr_netmask->addr); 00384 new_filter->out_port = out_port; 00385 new_filter->in_port = in_port; 00386 new_filter->priority = priority; 00387 new_filter->tos = tos; 00388 new_filter->filter_id = filter_id++; 00389 new_filter->function_ptr = fp_function[action].fn; 00390 00391 if(pico_tree_insert(&filter_tree, new_filter)) 00392 { 00393 PICO_FREE(new_filter); 00394 filter_id--; 00395 return 0; 00396 } 00397 00398 return new_filter->filter_id; 00399 } 00400 00401 int pico_ipv4_filter_del(uint32_t filter_id) 00402 { 00403 struct filter_node *node = NULL; 00404 struct filter_node dummy = { 0 }; 00405 00406 dummy.filter_id = filter_id; 00407 if((node = pico_tree_delete(&filter_tree, &dummy)) == NULL) 00408 { 00409 ipf_dbg("ipfilter> failed to delete filter :%d\n", filter_id); 00410 return -1; 00411 } 00412 00413 PICO_FREE(node); 00414 return 0; 00415 } 00416 00417 static int ipfilter_apply_filter(struct pico_frame *f, struct filter_node *pkt) 00418 { 00419 struct filter_node *filter_frame = NULL; 00420 filter_frame = pico_tree_findKey(&filter_tree, pkt); 00421 if(filter_frame) 00422 { 00423 filter_frame->function_ptr(filter_frame, f); 00424 return 1; 00425 } 00426 00427 return 0; 00428 } 00429 00430 int ipfilter(struct pico_frame *f) 00431 { 00432 struct filter_node temp; 00433 struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *) f->net_hdr; 00434 struct pico_trans *trans; 00435 struct pico_icmp4_hdr *icmp_hdr; 00436 00437 memset(&temp, 0u, sizeof(struct filter_node)); 00438 00439 temp.fdev = f->dev; 00440 temp.out_addr = ipv4_hdr->dst.addr; 00441 temp.in_addr = ipv4_hdr->src.addr; 00442 if ((ipv4_hdr->proto == PICO_PROTO_TCP) || (ipv4_hdr->proto == PICO_PROTO_UDP)) { 00443 trans = (struct pico_trans *) f->transport_hdr; 00444 temp.out_port = short_be(trans->dport); 00445 temp.in_port = short_be(trans->sport); 00446 } 00447 else if(ipv4_hdr->proto == PICO_PROTO_ICMP4) { 00448 icmp_hdr = (struct pico_icmp4_hdr *) f->transport_hdr; 00449 if(icmp_hdr->type == PICO_ICMP_UNREACH && icmp_hdr->type == PICO_ICMP_UNREACH_FILTER_PROHIB) 00450 return 0; 00451 } 00452 00453 temp.proto = ipv4_hdr->proto; 00454 temp.priority = f->priority; 00455 temp.tos = ipv4_hdr->tos; 00456 return ipfilter_apply_filter(f, &temp); 00457 } 00458
Generated on Tue Jul 12 2022 15:59:21 by 1.7.2