From edf14cf4b5edb148d7473f067d95e7bd1316900b Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 19 Apr 2000 11:26:44 +0000 Subject: Changes to allow matching (for delete) on part of a rule, for rules which change in the kernel (eg. ipt_limit). --- extensions/libipt_DNAT.c | 1 + extensions/libipt_LOG.c | 1 + extensions/libipt_MARK.c | 1 + extensions/libipt_REJECT.c | 1 + extensions/libipt_SNAT.c | 1 + extensions/libipt_TOS.c | 1 + extensions/libipt_icmp.c | 1 + extensions/libipt_limit.c | 1 + extensions/libipt_mac.c | 1 + extensions/libipt_mark.c | 1 + extensions/libipt_multiport.c | 1 + extensions/libipt_owner.c | 1 + extensions/libipt_standard.c | 1 + extensions/libipt_state.c | 1 + extensions/libipt_tcp.c | 17 +++++++----- extensions/libipt_tos.c | 1 + extensions/libipt_udp.c | 1 + extensions/libipt_unclean.c | 1 + include/iptables.h | 6 +++++ include/libiptc/libiptc.h | 4 ++- libiptc/libiptc.c | 61 +++++++++++++++++++++++++++---------------- 21 files changed, 74 insertions(+), 31 deletions(-) diff --git a/extensions/libipt_DNAT.c b/extensions/libipt_DNAT.c index e3c37222..6251cf1c 100644 --- a/extensions/libipt_DNAT.c +++ b/extensions/libipt_DNAT.c @@ -229,6 +229,7 @@ struct iptables_target dnat "DNAT", NETFILTER_VERSION, sizeof(struct ip_nat_multi_range), + sizeof(struct ip_nat_multi_range), &help, &init, &parse, diff --git a/extensions/libipt_LOG.c b/extensions/libipt_LOG.c index ce4adb23..d634cd55 100644 --- a/extensions/libipt_LOG.c +++ b/extensions/libipt_LOG.c @@ -245,6 +245,7 @@ struct iptables_target log "LOG", NETFILTER_VERSION, sizeof(struct ipt_log_info), + sizeof(struct ipt_log_info), &help, &init, &parse, diff --git a/extensions/libipt_MARK.c b/extensions/libipt_MARK.c index a7cb60c0..b8afe550 100644 --- a/extensions/libipt_MARK.c +++ b/extensions/libipt_MARK.c @@ -105,6 +105,7 @@ struct iptables_target mark "MARK", NETFILTER_VERSION, sizeof(struct ipt_mark_target_info), + sizeof(struct ipt_mark_target_info), &help, &init, &parse, diff --git a/extensions/libipt_REJECT.c b/extensions/libipt_REJECT.c index 3f5c128a..2c0b85b7 100644 --- a/extensions/libipt_REJECT.c +++ b/extensions/libipt_REJECT.c @@ -142,6 +142,7 @@ struct iptables_target reject "REJECT", NETFILTER_VERSION, sizeof(struct ipt_reject_info), + sizeof(struct ipt_reject_info), &help, &init, &parse, diff --git a/extensions/libipt_SNAT.c b/extensions/libipt_SNAT.c index 86ba39b9..f769cd4e 100644 --- a/extensions/libipt_SNAT.c +++ b/extensions/libipt_SNAT.c @@ -229,6 +229,7 @@ struct iptables_target snat "SNAT", NETFILTER_VERSION, sizeof(struct ip_nat_multi_range), + sizeof(struct ip_nat_multi_range), &help, &init, &parse, diff --git a/extensions/libipt_TOS.c b/extensions/libipt_TOS.c index f01fc264..ed599005 100644 --- a/extensions/libipt_TOS.c +++ b/extensions/libipt_TOS.c @@ -158,6 +158,7 @@ struct iptables_target tos "TOS", NETFILTER_VERSION, sizeof(struct ipt_tos_target_info), + sizeof(struct ipt_tos_target_info), &help, &init, &parse, diff --git a/extensions/libipt_icmp.c b/extensions/libipt_icmp.c index 65857ce3..0a47e412 100644 --- a/extensions/libipt_icmp.c +++ b/extensions/libipt_icmp.c @@ -280,6 +280,7 @@ struct iptables_match icmp "icmp", NETFILTER_VERSION, sizeof(struct ipt_icmp), + sizeof(struct ipt_icmp), &help, &init, &parse, diff --git a/extensions/libipt_limit.c b/extensions/libipt_limit.c index b6cc74f2..822109bf 100644 --- a/extensions/libipt_limit.c +++ b/extensions/libipt_limit.c @@ -181,6 +181,7 @@ struct iptables_match limit "limit", NETFILTER_VERSION, sizeof(struct ipt_rateinfo), + offsetof(struct ipt_rateinfo, prev), &help, &init, &parse, diff --git a/extensions/libipt_mac.c b/extensions/libipt_mac.c index 36d89692..f740ecc5 100644 --- a/extensions/libipt_mac.c +++ b/extensions/libipt_mac.c @@ -129,6 +129,7 @@ struct iptables_match mac "mac", NETFILTER_VERSION, sizeof(struct ipt_mac_info), + sizeof(struct ipt_mac_info), &help, &init, &parse, diff --git a/extensions/libipt_mark.c b/extensions/libipt_mark.c index dcf54488..2cd6193b 100644 --- a/extensions/libipt_mark.c +++ b/extensions/libipt_mark.c @@ -113,6 +113,7 @@ struct iptables_match mark "mark", NETFILTER_VERSION, sizeof(struct ipt_mark_info), + sizeof(struct ipt_mark_info), &help, &init, &parse, diff --git a/extensions/libipt_multiport.c b/extensions/libipt_multiport.c index 727f95fc..8c58bddd 100644 --- a/extensions/libipt_multiport.c +++ b/extensions/libipt_multiport.c @@ -246,6 +246,7 @@ struct iptables_match multiport "multiport", NETFILTER_VERSION, sizeof(struct ipt_multiport), + sizeof(struct ipt_multiport), &help, &init, &parse, diff --git a/extensions/libipt_owner.c b/extensions/libipt_owner.c index 29311022..027f5383 100644 --- a/extensions/libipt_owner.c +++ b/extensions/libipt_owner.c @@ -204,6 +204,7 @@ struct iptables_match owner "owner", NETFILTER_VERSION, sizeof(struct ipt_owner_info), + sizeof(struct ipt_owner_info), &help, &init, &parse, diff --git a/extensions/libipt_standard.c b/extensions/libipt_standard.c index 9a746b2d..c63669f0 100644 --- a/extensions/libipt_standard.c +++ b/extensions/libipt_standard.c @@ -52,6 +52,7 @@ struct iptables_target standard "standard", NETFILTER_VERSION, sizeof(int), + sizeof(int), &help, &init, &parse, diff --git a/extensions/libipt_state.c b/extensions/libipt_state.c index 19751d72..d3dcbc2d 100644 --- a/extensions/libipt_state.c +++ b/extensions/libipt_state.c @@ -147,6 +147,7 @@ struct iptables_match state "state", NETFILTER_VERSION, sizeof(struct ipt_state_info), + sizeof(struct ipt_state_info), &help, &init, &parse, diff --git a/extensions/libipt_tcp.c b/extensions/libipt_tcp.c index 2febc28c..276d0e2a 100644 --- a/extensions/libipt_tcp.c +++ b/extensions/libipt_tcp.c @@ -308,21 +308,23 @@ print_option(u_int8_t option, int invert, int numeric) static void print_tcpf(u_int8_t flags) { - int sole_flag = 1; + int have_flag = 0; - do { + while (flags) { unsigned int i; - /* Terminates because last flag is 0 */ - for (i = 0; !(flags & tcp_flag_names[i].flag); i++); + for (i = 0; (flags & tcp_flag_names[i].flag) == 0; i++); - if (!sole_flag) + if (have_flag) printf(","); printf("%s", tcp_flag_names[i].name); - sole_flag = 0; + have_flag = 1; flags &= ~tcp_flag_names[i].flag; - } while (flags); + } + + if (!have_flag) + printf("NONE"); } static void @@ -424,6 +426,7 @@ struct iptables_match tcp "tcp", NETFILTER_VERSION, sizeof(struct ipt_tcp), + sizeof(struct ipt_tcp), &help, &init, &parse, diff --git a/extensions/libipt_tos.c b/extensions/libipt_tos.c index 6d2d7724..99c89ea7 100644 --- a/extensions/libipt_tos.c +++ b/extensions/libipt_tos.c @@ -156,6 +156,7 @@ struct iptables_match tos "tos", NETFILTER_VERSION, sizeof(struct ipt_tos_info), + sizeof(struct ipt_tos_info), &help, &init, &parse, diff --git a/extensions/libipt_udp.c b/extensions/libipt_udp.c index 603a4860..507937b1 100644 --- a/extensions/libipt_udp.c +++ b/extensions/libipt_udp.c @@ -236,6 +236,7 @@ struct iptables_match udp "udp", NETFILTER_VERSION, sizeof(struct ipt_udp), + sizeof(struct ipt_udp), &help, &init, &parse, diff --git a/extensions/libipt_unclean.c b/extensions/libipt_unclean.c index 50f62bdc..bef513e6 100644 --- a/extensions/libipt_unclean.c +++ b/extensions/libipt_unclean.c @@ -51,6 +51,7 @@ struct iptables_match unclean "unclean", NETFILTER_VERSION, 0, + 0, &help, &init, &parse, diff --git a/include/iptables.h b/include/iptables.h index 9b1a4a16..1ddd8712 100644 --- a/include/iptables.h +++ b/include/iptables.h @@ -15,6 +15,9 @@ struct iptables_match /* Size of match data. */ size_t size; + /* Size of match data relevent for userspace comparison purposes */ + size_t userspacesize; + /* Function which prints out usage message. */ void (*help)(void); @@ -59,6 +62,9 @@ struct iptables_target /* Size of target data. */ size_t size; + /* Size of target data relevent for userspace comparison purposes */ + size_t userspacesize; + /* Function which prints out usage message. */ void (*help)(void); diff --git a/include/libiptc/libiptc.h b/include/libiptc/libiptc.h index 4a964e03..0a491071 100644 --- a/include/libiptc/libiptc.h +++ b/include/libiptc/libiptc.h @@ -73,9 +73,11 @@ int iptc_append_entry(const ipt_chainlabel chain, const struct ipt_entry *e, iptc_handle_t *handle); -/* Delete the first rule in `chain' which matches `e'. */ +/* Delete the first rule in `chain' which matches `e', subject to + matchmask (array of length == origfw) */ int iptc_delete_entry(const ipt_chainlabel chain, const struct ipt_entry *origfw, + unsigned char *matchmask, iptc_handle_t *handle); /* Delete the rule in position `rulenum' in `chain'. */ diff --git a/libiptc/libiptc.c b/libiptc/libiptc.c index de819f2b..a90d46ea 100644 --- a/libiptc/libiptc.c +++ b/libiptc/libiptc.c @@ -16,13 +16,14 @@ #include #include #include -#include +#include #if !defined(__GLIBC__) || (__GLIBC__ < 2) typedef unsigned int socklen_t; #endif #include +#include #define IP_VERSION 4 #define IP_OFFSET 0x1FFF @@ -1000,10 +1001,12 @@ iptc_append_entry(const ipt_chainlabel chain, static inline int match_different(const struct ipt_entry_match *a, - const char *a_elems, - const char *b_elems) + const unsigned char *a_elems, + const unsigned char *b_elems, + unsigned char **maskptr) { const struct ipt_entry_match *b; + unsigned int i; /* Offset of b is the same as a. */ b = (void *)b_elems + ((char *)a-a_elems); @@ -1014,28 +1017,38 @@ match_different(const struct ipt_entry_match *a, if (strcmp(a->u.name, b->u.name) != 0) return 1; - /* FIXME: This is really, really gross --RR */ - if (strcmp(a->u.name,"limit") == 0) { - /* Special case, the kernel writes in this data, so we - * need to make sure that we only check the parts - * that are user specified */ - if (((struct ipt_rateinfo *)a->data)->avg - != ((struct ipt_rateinfo *)b->data)->avg - || ((struct ipt_rateinfo *)a->data)->burst - != ((struct ipt_rateinfo *)b->data)->burst) + *maskptr += sizeof(*a); + + for (i = 0; i < a->match_size - sizeof(*a); i++) + if (((a->data[i] ^ b->data[i]) & (*maskptr)[i]) != 0) + return 1; + *maskptr += i; + return 0; +} + +static inline int +target_different(const unsigned char *a_targdata, + const unsigned char *b_targdata, + unsigned int tdatasize, + const unsigned char *mask) +{ + unsigned int i; + for (i = 0; i < tdatasize; i++) + if (((a_targdata[i] ^ b_targdata[i]) & mask[i]) != 0) return 1; - } else if (memcmp(a->data, b->data, a->match_size - sizeof(*a)) != 0) - return 1; return 0; } static inline int -is_same(const struct ipt_entry *a, const struct ipt_entry *b) +is_same(const struct ipt_entry *a, const struct ipt_entry *b, + unsigned char *matchmask) { unsigned int i; struct ipt_entry_target *ta, *tb; + unsigned char *mptr; + /* Always compare head structures: ignore mask here. */ if (a->ip.src.s_addr != b->ip.src.s_addr || a->ip.dst.s_addr != b->ip.dst.s_addr || a->ip.smsk.s_addr != b->ip.smsk.s_addr @@ -1063,7 +1076,8 @@ is_same(const struct ipt_entry *a, const struct ipt_entry *b) || a->next_offset != b->next_offset) return 0; - if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems)) + mptr = matchmask + sizeof(struct ipt_entry); + if (IPT_MATCH_ITERATE(a, match_different, a->elems, b->elems, &mptr)) return 0; ta = ipt_get_target((struct ipt_entry *)a); @@ -1072,12 +1086,12 @@ is_same(const struct ipt_entry *a, const struct ipt_entry *b) return 0; if (strcmp(ta->u.name, tb->u.name) != 0) return 0; - - /* FIXME: If kernel modifies these, then we never match --RR */ - - if (memcmp(ta->data, tb->data, ta->target_size - sizeof(*ta)) != 0) - return 0; - + + mptr += sizeof(*ta) + if (target_different(ta->data, tb->data, + ta->target_size - sizeof(*ta), mptr)) + return 0; + return 1; } @@ -1085,6 +1099,7 @@ is_same(const struct ipt_entry *a, const struct ipt_entry *b) int iptc_delete_entry(const ipt_chainlabel chain, const struct ipt_entry *origfw, + unsigned char *matchmask, iptc_handle_t *handle) { unsigned int offset, lastoff; @@ -1120,7 +1135,7 @@ iptc_delete_entry(const ipt_chainlabel chain, printf("Deleting:\n"); dump_entry(newe); #endif - if (is_same(e, fw)) { + if (is_same(e, fw, matchmask)) { int ret; ret = delete_rules(1, e->next_offset, offset, entry2index(*handle, e), -- cgit v1.2.3