Review: Needs Fixing General remarks --------------- To clarify the review, I'll add an <importance> flag to each comment. <importance> is either [H]igh, [M]edium, or [L]ow or something else that will be self explaining. Everything with importance High and Medium is sufficiently severe in my opinion to block the merge (so I won't give an 'approve' rating) so these things need to be fixed or addressed in my opinion (things that break HIPL get a High, things that do not conform to project policy or I find unacceptable for some other reason get a Medium). Importance Low is something which I would personally like to see addressed but which are ok, though not great, to merge as is. If [H] or [M] is followed by a question, that's a point where I need more information to make a vote on the merge. No real need to change the code right away. I know that this may sound overly formal and a bit full of myself but I hope that it simply helps the branch author to more easily identify important comments, what blocks a merge in my opinion and what is just a remark. Review ------ > === modified file 'firewall/conntrack.c' > --- firewall/conntrack.c 2010-12-13 19:09:27 +0000 > +++ firewall/conntrack.c 2010-12-13 21:28:35 +0000 > @@ -50,6 +52,7 @@ > #include <openssl/dsa.h> > #include <openssl/rsa.h> > #include <sys/time.h> > +#include <linux/netfilter_ipv4.h> > > #include "lib/core/builder.h" > #include "lib/core/debug.h" [H] license: does the inclusion introduce a GPL infection? > @@ -73,9 +76,40 @@ > #include "config.h" > #include "reinject.h" > > - > -struct dlist *hip_list = NULL; > -struct dlist *esp_list = NULL; > +#ifdef CONFIG_HIP_DEBUG > +// this improves our chances of finding bugs in the timeout code > +#define DEFAULT_CONNECTION_TIMEOUT 20; // 20 seconds > +#define DEFAULT_CLEANUP_INTERVAL 10; // 10 seconds > +#else > +#define DEFAULT_CONNECTION_TIMEOUT (60 * 5); // 5 minutes > +#define DEFAULT_CLEANUP_INTERVAL (60 * 60); // 1 minute > +#endif [M] style & policy: use constants instead of macros > +/** > + * Interval between sweeps in hip_fw_conntrack_periodic_cleanup(), > + * in Seconds. [L] docs: Seconds -> seconds > @@ -116,7 +149,7 @@ > * > * @param hiptuple HIP tuple > */ > -static void print_tuple(const struct hip_tuple *hiptuple) > +static void print_tuple(DBG const struct hip_tuple *hiptuple) [L] style: const correctness for pointer arguments. May apply to other functions. Please check. > @@ -319,23 +352,147 @@ > } > > /** > - * Insert an address into a list of addresses. If same address exists > already, > - * the update_id is replaced with the new value. > - * > - * @param addr_list the address list > - * @param addr the address to be added > - * @param upd_id update id > - * > - * @return the address list > - */ > -static struct slist *update_esp_address(struct slist *addr_list, > - const struct in6_addr *addr, > - const uint32_t *upd_id) > -{ > - struct esp_address *esp_addr = get_esp_address(addr_list, addr); > + * Forward this spi/dest combo via iptables rather than userspace > + * dispatching, or delete the corresponding rules. > + * > + * @param esp_tuple Extract SPI and connection info from this tuple. > + * @param dest The newly added address. > + * @param insert Remove rule if false, add it otherwise. > + * @return 0 on success, -1 otherwise. > + * > + * @todo Test rules using userspace_ipsec, Relay, LSI, sys-opp, midauth, > + * light-update and esp_prot configurations. > + * @todo Test with different byte ordering. [L] I don't like TODOs in trunk. Especially if they effectively say that the code has poor quality due to lazyness ;-) > + * > + * @see update_esp_address > + * @see free_esp_tuple > + */ > +static int hip_fw_manage_esp_rule(const struct esp_tuple *esp_tuple, > + const struct in6_addr *dest, bool insert) > +{ > + int err = 0; > + const char *flag = insert ? "-I" : "-D"; > + const char *table = NULL; > + > + if (hip_userspace_ipsec || prefer_userspace) { > + return 0; > + } > + > + HIP_ASSERT(esp_tuple); > + HIP_ASSERT(dest); > + > + if (esp_tuple->esp_prot_tfm > ESP_PROT_TFM_UNUSED) { > + HIP_DEBUG("ESP Transforms requested; not handled via iptables " > + "since we need to inspect packets\n"); > + return 0; > + } > + > + if (esp_tuple->tuple->esp_relay) { > + HIP_DEBUG("ESP Relay requested; not handled via iptables " > + "since we need packet rewriting\n"); > + return 0; > + } [L] design/style: It seems strange to me that 'success' is returned when the function didn't actually complete successfully. It might make sense to have a return value that says 'you called this function under conditions with which a call does not make sense'. > + err = system_printf("ip6tables %s %s -p 50 " > + "-d %s -m esp --espspi 0x%08X -j ACCEPT", > + flag, table, daddr, esp_tuple->spi); > + } > + > +out_err: > + if (err == EXIT_SUCCESS) { > + total_esp_rules_count += (insert ? 1 : -1); > + HIP_DEBUG("total_esp_rules_count = %d\n", total_esp_rules_count); > + } > + return err; > +} [L] style: it's counter-intuitive to have non-error code after the label out_err. > +/** > + * Forward all spi/dest combos associated with @a esp_tuple via iptables, > + * or delete the corresponding rules. [L] docs: wouldn't it be more correct to say something like 'Insert or remove all iptables rules matching a given combination of SPIs and destination [somethings]'? > + * > + * @param esp_tuple Extract SPI and connection info from this tuple. [L] docs: Conveys an implementation detail, not a useful hint on the effect of this parameter on the service this function provides. > + * @param insert remove all rules if zero, add otherwise. > + * > + * @see hip_fw_manage_esp_rule > + */ > +void hip_fw_manage_esp_tuple(const struct esp_tuple *esp_tuple, bool insert) [M] const correctness > +{ > + struct slist *lst = esp_tuple->dst_addr_list; > + while (lst) { > + hip_fw_manage_esp_rule(esp_tuple, lst->data, insert); > + lst = lst->next; > + } > +} [L] style: personally, I would write this as a for instead of a while loop because it perfectly matches the for loop pattern > + > +/** > + * Insert a destination address into an esp_tuple. If same address exists > already, > + * the update_id is replaced with the new value instead. [M] docs: does this sentence really reflect the service provided by the function? I think the function actually changes iptables rules, right? [L] docs: rewrite to reflect actual functionality > @@ -425,9 +584,11 @@ > * initialize and store a new HIP/ESP connnection into the connection table > * > * @param data the connection-related data to be inserted > + * @param ctx the context [M] docs: please make the documentation more helpful for a caller > @@ -1956,3 +2088,273 @@ > HIP_DEBUG("get_tuple_by_hits: no connection found\n"); > return NULL; > } > + > +/** > + * Info about currently set esp rules and their respective packet counts. > + */ > +struct esp_rule_status { > + uint32_t spi; /**< security parameter index */ > + struct in6_addr addr; /**< dest address (may be IPV4-mapped) */ > + unsigned int packet_count; /**< number of packets received */ > +}; [M] Hm, I think we've discussed the topic of keeping track of packet counts in HIPL before. I think we came to the conclusion that it would be less error-prone and more efficient to use iptable's internal counters instead. Above all, it would significantly reduce code complexity. If that is correct, I do not want the current code to be merged into trunk. > +/** > + * Do some necessary bookkeeping concerning connection tracking. > + * Currently, this only makes sure that stale locations will be removed. > + * The actual tasks will be run at most once per @c connection_timeout > + * seconds, no matter how often you call the function. > + * > + * @note Don't call this from a thread or timer, since most of hipfw is not > + * reentrant (and so this function isn't either). > + */ > +void hip_fw_conntrack_periodic_cleanup(void) > +{ > + int err = 0; > + struct slist *iter_conn = NULL; > + struct esp_rule_status *snapshot = NULL; > + static time_t last_check = 0; // timestamp of last call > + const time_t now = time(NULL); > + > + if (connection_timeout == 0) { > + // timeout disabled > + return; > + } > + > + HIP_ASSERT(now >= last_check); > + if (last_check != 0 && now - last_check < cleanup_interval) { > + // don't sweep yet > + return; > + } > + > + HIP_DEBUG("Commencing periodic cleanup\n"); > + > + last_check = now; > + > + // If connections are covered by iptables rules, we rely on packet > + // counters to update timestamps indirectly. > + // By taking care of this now, the affected connections won't be > + // examined again in the conn_list loop later on. > + > + if (total_esp_rules_count > 0) { > + const size_t sz = sizeof(*snapshot) * total_esp_rules_count; > + size_t n = 0; > + > + HIP_IFEL(!(snapshot = malloc(sz)), 1, "Insufficient memory\n"); > + [M] style: Could a local array variable be used instead of malloc()? [L] style: if possible, use a local array variable instead of heap memory to simplify memory management > + n += populate_snapshot("iptables -nvL", &snapshot[n], > total_esp_rules_count - n); > + HIP_ASSERT(n <= total_esp_rules_count); > + > + n += populate_snapshot("ip6tables -nvL", &snapshot[n], > total_esp_rules_count - n); > + HIP_ASSERT(n <= total_esp_rules_count); > + > + struct dlist *iter_esp = esp_list; > + while (iter_esp) { > + update_esp_tuple_timestamp(now, snapshot, n, iter_esp->data); > + iter_esp = iter_esp->next; > + } > + free(snapshot); > + snapshot = NULL; > + } > + > + // do the actual cleaning now > + > + iter_conn = conn_list; > + while (iter_conn) { > + struct connection *conn = (struct connection*) iter_conn->data; [M] style: could the cast be avoided? [L] style: remove cast if possible > === modified file 'firewall/firewall_defines.h' > --- firewall/firewall_defines.h 2010-12-13 19:09:27 +0000 > +++ firewall/firewall_defines.h 2010-12-13 21:28:35 +0000 > @@ -78,11 +79,18 @@ > // null update_id can be removed. > }; > > +/** > + * Stores information about one ESP connection endpoint (i.e., one SPI). > + * > + * @todo Write allocator/deallocator for automatic synching with ::esp_list. [M] docs: specify why this not necessary right now but why it could be necessary at some stage. Developers need to be able to understand the basic implications of this TODO without having to read through hundreds of lines of potentially affected code. > @@ -119,6 +127,11 @@ > struct tuple *tuple; > }; > > +/** > + * Connection endpoint. > + * > + * @todo Write allocator/deallocator for automatic syncing with ::hip_list. [M] docs: see above. > @@ -129,18 +142,26 @@ > int direction; > struct connection *connection; > int state; > + int hook; > uint32_t lupdate_seq; > int esp_relay; > struct in6_addr esp_relay_daddr; > in_port_t esp_relay_dport; > }; > > +/** > + * A connection (i.e., two tuples). [M] docs: not helpful. A connection between what? What tuples? Why do we need this data structure? > + * alloc/dealloc using insert_new_connection() or > + * remove_connection(), respectively. > + */ > struct connection { > === modified file 'firewall/hslist.c' > --- firewall/hslist.c 2010-12-13 19:09:27 +0000 > +++ firewall/hslist.c 2010-12-13 21:28:35 +0000 > @@ -129,3 +129,21 @@ > > return list; > } > + > +/** > + * find an element in the linked list [L] docs: Grammatically correct English sentences are very desirable in doxygen documentation. > + * > + * @param list the linked list > + * @param data the element to find > + * @return the element in the linked list > + */ > +struct slist *find_in_slist(struct slist *list, void *data) [M] const correctness > === modified file 'hipd/hiprelay.c' > --- hipd/hiprelay.c 2010-11-30 14:50:30 +0000 > +++ hipd/hiprelay.c 2010-12-13 21:28:35 +0000 > @@ -1015,16 +1015,16 @@ > * > * @param r the HIP control message to be relayed > * @param type_hdr message type > - * @param r_saddr the original source address > - * @param r_daddr the original destination address > + * @param r_saddr (unused) the original source address > + * @param r_daddr (unused) the original destination address [M] what is the point of adding unused function arguments to an already crowded signature? > === modified file 'lib/core/debug.h' > --- lib/core/debug.h 2010-12-06 19:58:46 +0000 > +++ lib/core/debug.h 2010-12-13 21:28:35 +0000 > @@ -29,6 +29,7 @@ > #include <stdarg.h> > #include <stdint.h> > > +#include "config.h" > #include "protodefs.h" > > /* includes filename, line number and max(debug_prefix[]) */ > @@ -295,10 +296,17 @@ > #define HIP_INFO_LSI(str, lsi) hip_print_lsi(DEBUG_LEVEL_INFO, __FILE__, > __LINE__, __FUNCTION__, str, lsi) > #define HIP_INFO_INADDR(str, in) hip_print_lsi(DEBUG_LEVEL_INFO, __FILE__, > __LINE__, __FUNCTION__, str, in) > > +#ifdef CONFIG_HIP_DEBUG > #define HIP_DEBUG_HIT(str, hit) hip_print_hit(DEBUG_LEVEL_DEBUG, __FILE__, > __LINE__, __FUNCTION__, str, hit) > #define HIP_DEBUG_IN6ADDR(str, in6) hip_print_hit(DEBUG_LEVEL_DEBUG, > __FILE__, __LINE__, __FUNCTION__, str, in6) > #define HIP_DEBUG_LSI(str, lsi) hip_print_lsi(DEBUG_LEVEL_DEBUG, __FILE__, > __LINE__, __FUNCTION__, str, lsi) > #define HIP_DEBUG_INADDR(str, in) hip_print_lsi(DEBUG_LEVEL_DEBUG, > __FILE__, __LINE__, __FUNCTION__, str, in) > +#else > +#define HIP_DEBUG_HIT(str, hit) do {} while (0) > +#define HIP_DEBUG_IN6ADDR(str, in6) do {} while (0) > +#define HIP_DEBUG_LSI(str, lsi) do {} while (0) > +#define HIP_DEBUG_INADDR(str, in) do {} while (0) > +#endif [M] Is this modification relevant to this branch? I think it should be committed separately. -- https://code.launchpad.net/~diego-biurrun/hipl/hipfw-performance/+merge/43568 Your team HIPL core team is requested to review the proposed merge of lp:~diego-biurrun/hipl/hipfw-performance into lp:hipl.