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

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers pico_ipfilter.c Source File

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