Unified · Split
| @@ -223,4 +223,7 @@ config LEDS_TRIGGER_DEFAULT_ON · 222 unmodified lines | ||
| 223 | 223 | This allows LEDs to be initialised in the ON state. |
| 224 | 224 | If unsure, say Y. |
| 225 | 225 | |
| 226 | +comment "iptables trigger is under Netfilter config (LED target)" | |
| 227 | + depends on LEDS_TRIGGERS | |
| 228 | + | |
| 226 | 229 | endif # NEW_LEDS |
| @@ -7,16 +7,21 @@ header-y += xt_CLASSIFY.h · 6 unmodified lines | ||
| 7 | 7 | header-y += xt_CONNMARK.h |
| 8 | 8 | header-y += xt_CONNSECMARK.h |
| 9 | 9 | header-y += xt_DSCP.h |
| 10 | +header-y += xt_LED.h | |
| 10 | 11 | header-y += xt_MARK.h |
| 11 | 12 | header-y += xt_NFLOG.h |
| 12 | 13 | header-y += xt_NFQUEUE.h |
| 13 | 14 | header-y += xt_RATEEST.h |
| 14 | 15 | header-y += xt_SECMARK.h |
| 15 | 16 | header-y += xt_TCPMSS.h |
| 17 | +header-y += xt_TCPOPTSTRIP.h | |
| 18 | +header-y += xt_TPROXY.h | |
| 16 | 19 | header-y += xt_comment.h |
| 17 | 20 | header-y += xt_connbytes.h |
| 21 | +header-y += xt_connlimit.h | |
| 18 | 22 | header-y += xt_connmark.h |
| 19 | 23 | header-y += xt_conntrack.h |
| 24 | +header-y += xt_cluster.h | |
| 20 | 25 | header-y += xt_dccp.h |
| 21 | 26 | header-y += xt_dscp.h |
| 22 | 27 | header-y += xt_esp.h |
| @@ -30,6 +35,7 @@ header-y += xt_mark.h · 7 unmodified lines | ||
| 30 | 35 | header-y += xt_multiport.h |
| 31 | 36 | header-y += xt_owner.h |
| 32 | 37 | header-y += xt_pkttype.h |
| 38 | +header-y += xt_quota.h | |
| 33 | 39 | header-y += xt_rateest.h |
| 34 | 40 | header-y += xt_realm.h |
| 35 | 41 | header-y += xt_recent.h |
| @@ -39,6 +45,8 @@ header-y += xt_statistic.h · 3 unmodified lines | ||
| 39 | 45 | header-y += xt_string.h |
| 40 | 46 | header-y += xt_tcpmss.h |
| 41 | 47 | header-y += xt_tcpudp.h |
| 48 | +header-y += xt_time.h | |
| 49 | +header-y += xt_u32.h | |
| 42 | 50 | |
| 43 | 51 | unifdef-y += nf_conntrack_common.h |
| 44 | 52 | unifdef-y += nf_conntrack_ftp.h |
| @@ -76,6 +76,7 @@ extern int nfnetlink_subsys_unregister(const struct nfnetlink_subsystem *n); · 75 unmodified lines | ||
| 76 | 76 | extern int nfnetlink_has_listeners(unsigned int group); |
| 77 | 77 | extern int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, |
| 78 | 78 | int echo); |
| 79 | +extern void nfnetlink_set_err(u32 pid, u32 group, int error); | |
| 79 | 80 | extern int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags); |
| 80 | 81 | |
| 81 | 82 | extern void nfnl_lock(void); |
| @@ -349,23 +349,22 @@ struct xt_table · 348 unmodified lines | ||
| 349 | 349 | { |
| 350 | 350 | struct list_head list; |
| 351 | 351 | |
| 352 | − /* A unique name... */ | |
| 353 | − const char name[XT_TABLE_MAXNAMELEN]; | |
| 354 | − | |
| 355 | 352 | /* What hooks you will enter on */ |
| 356 | 353 | unsigned int valid_hooks; |
| 357 | 354 | |
| 358 | 355 | /* Lock for the curtain */ |
| 359 | − rwlock_t lock; | |
| 356 | + struct mutex lock; | |
| 360 | 357 | |
| 361 | 358 | /* Man behind the curtain... */ |
| 362 | − //struct ip6t_table_info *private; | |
| 363 | − void *private; | |
| 359 | + struct xt_table_info *private; | |
| 364 | 360 | |
| 365 | 361 | /* Set this to THIS_MODULE if you are a module, otherwise NULL */ |
| 366 | 362 | struct module *me; |
| 367 | 363 | |
| 368 | 364 | u_int8_t af; /* address/protocol family */ |
| 365 | + | |
| 366 | + /* A unique name... */ | |
| 367 | + const char name[XT_TABLE_MAXNAMELEN]; | |
| 369 | 368 | }; |
| 370 | 369 | |
| 371 | 370 | #include <linux/netfilter_ipv4.h> |
| @@ -386,7 +385,7 @@ struct xt_table_info · 14 unmodified lines | ||
| 386 | 385 | |
| 387 | 386 | /* ipt_entry tables: one per CPU */ |
| 388 | 387 | /* Note : this field MUST be the last one, see XT_TABLE_INFO_SZ */ |
| 389 | − char *entries[1]; | |
| 388 | + void *entries[1]; | |
| 390 | 389 | }; |
| 391 | 390 | |
| 392 | 391 | #define XT_TABLE_INFO_SZ (offsetof(struct xt_table_info, entries) \ |
| @@ -433,6 +432,8 @@ extern void xt_proto_fini(struct net *net, u_int8_t af); · 40 unmodified lines | ||
| 433 | 432 | |
| 434 | 433 | extern struct xt_table_info *xt_alloc_table_info(unsigned int size); |
| 435 | 434 | extern void xt_free_table_info(struct xt_table_info *info); |
| 435 | +extern void xt_table_entry_swap_rcu(struct xt_table_info *old, | |
| 436 | + struct xt_table_info *new); | |
| 436 | 437 | |
| 437 | 438 | #ifdef CONFIG_COMPAT |
| 438 | 439 | #include <net/compat.h> |
| @@ -0,0 +1,13 @@ | ||
| 1 | +#ifndef _XT_LED_H | |
| 2 | +#define _XT_LED_H | |
| 3 | + | |
| 4 | +struct xt_led_info { | |
| 5 | + char id[27]; /* Unique ID for this trigger in the LED class */ | |
| 6 | + __u8 always_blink; /* Blink even if the LED is already on */ | |
| 7 | + __u32 delay; /* Delay until LED is switched off after trigger */ | |
| 8 | + | |
| 9 | + /* Kernel data used in the module */ | |
| 10 | + void *internal_data __attribute__((aligned(8))); | |
| 11 | +}; | |
| 12 | + | |
| 13 | +#endif /* _XT_LED_H */ | |
| @@ -0,0 +1,15 @@ | ||
| 1 | +#ifndef _XT_CLUSTER_MATCH_H | |
| 2 | +#define _XT_CLUSTER_MATCH_H | |
| 3 | + | |
| 4 | +enum xt_cluster_flags { | |
| 5 | + XT_CLUSTER_F_INV = (1 << 0) | |
| 6 | +}; | |
| 7 | + | |
| 8 | +struct xt_cluster_match_info { | |
| 9 | + u_int32_t total_nodes; | |
| 10 | + u_int32_t node_mask; | |
| 11 | + u_int32_t hash_seed; | |
| 12 | + u_int32_t flags; | |
| 13 | +}; | |
| 14 | + | |
| 15 | +#endif /* _XT_CLUSTER_MATCH_H */ | |
| @@ -4,6 +4,8 @@ · 3 unmodified lines | ||
| 4 | 4 | /* timings are in milliseconds. */ |
| 5 | 5 | #define XT_LIMIT_SCALE 10000 |
| 6 | 6 | |
| 7 | +struct xt_limit_priv; | |
| 8 | + | |
| 7 | 9 | /* 1/10,000 sec period => max of 10,000/sec. Min rate is then 429490 |
| 8 | 10 | seconds, or one every 59 hours. */ |
| 9 | 11 | struct xt_rateinfo { |
| @@ -11,11 +13,10 @@ struct xt_rateinfo { · 1 unmodified line | ||
| 11 | 13 | u_int32_t burst; /* Period multiplier for upper limit. */ |
| 12 | 14 | |
| 13 | 15 | /* Used internally by the kernel */ |
| 14 | − unsigned long prev; | |
| 15 | − u_int32_t credit; | |
| 16 | + unsigned long prev; /* moved to xt_limit_priv */ | |
| 17 | + u_int32_t credit; /* moved to xt_limit_priv */ | |
| 16 | 18 | u_int32_t credit_cap, cost; |
| 17 | 19 | |
| 18 | − /* Ugly, ugly fucker. */ | |
| 19 | − struct xt_rateinfo *master; | |
| 20 | + struct xt_limit_priv *master; | |
| 20 | 21 | }; |
| 21 | 22 | #endif /*_XT_RATE_H*/ |
| @@ -6,13 +6,15 @@ enum xt_quota_flags { · 5 unmodified lines | ||
| 6 | 6 | }; |
| 7 | 7 | #define XT_QUOTA_MASK 0x1 |
| 8 | 8 | |
| 9 | +struct xt_quota_priv; | |
| 10 | + | |
| 9 | 11 | struct xt_quota_info { |
| 10 | 12 | u_int32_t flags; |
| 11 | 13 | u_int32_t pad; |
| 12 | 14 | |
| 13 | 15 | /* Used internally by the kernel */ |
| 14 | 16 | aligned_u64 quota; |
| 15 | − struct xt_quota_info *master; | |
| 17 | + struct xt_quota_priv *master; | |
| 16 | 18 | }; |
| 17 | 19 | |
| 18 | 20 | #endif /* _XT_QUOTA_H */ |
| @@ -13,6 +13,8 @@ enum xt_statistic_flags { · 12 unmodified lines | ||
| 13 | 13 | }; |
| 14 | 14 | #define XT_STATISTIC_MASK 0x1 |
| 15 | 15 | |
| 16 | +struct xt_statistic_priv; | |
| 17 | + | |
| 16 | 18 | struct xt_statistic_info { |
| 17 | 19 | u_int16_t mode; |
| 18 | 20 | u_int16_t flags; |
| @@ -23,11 +25,10 @@ struct xt_statistic_info { · 4 unmodified lines | ||
| 23 | 25 | struct { |
| 24 | 26 | u_int32_t every; |
| 25 | 27 | u_int32_t packet; |
| 26 | − /* Used internally by the kernel */ | |
| 27 | − u_int32_t count; | |
| 28 | + u_int32_t count; /* unused */ | |
| 28 | 29 | } nth; |
| 29 | 30 | } u; |
| 30 | − struct xt_statistic_info *master __attribute__((aligned(8))); | |
| 31 | + struct xt_statistic_priv *master __attribute__((aligned(8))); | |
| 31 | 32 | }; |
| 32 | 33 | |
| 33 | 34 | #endif /* _XT_STATISTIC_H */ |
| @@ -11,6 +11,7 @@ header-y += ip6t_length.h · 10 unmodified lines | ||
| 11 | 11 | header-y += ip6t_limit.h |
| 12 | 12 | header-y += ip6t_mac.h |
| 13 | 13 | header-y += ip6t_mark.h |
| 14 | +header-y += ip6t_mh.h | |
| 14 | 15 | header-y += ip6t_multiport.h |
| 15 | 16 | header-y += ip6t_opts.h |
| 16 | 17 | header-y += ip6t_owner.h |
| @@ -287,7 +287,7 @@ static inline int nf_ct_is_untracked(const struct sk_buff *skb) · 286 unmodified lines | ||
| 287 | 287 | |
| 288 | 288 | extern int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp); |
| 289 | 289 | extern unsigned int nf_conntrack_htable_size; |
| 290 | −extern int nf_conntrack_max; | |
| 290 | +extern unsigned int nf_conntrack_max; | |
| 291 | 291 | |
| 292 | 292 | #define NF_CT_STAT_INC(net, count) \ |
| 293 | 293 | (per_cpu_ptr((net)->ct.stat, raw_smp_processor_id())->count++) |
| @@ -90,10 +90,7 @@ struct nf_conntrack_l4proto · 89 unmodified lines | ||
| 90 | 90 | struct module *me; |
| 91 | 91 | }; |
| 92 | 92 | |
| 93 | −/* Existing built-in protocols */ | |
| 94 | −extern struct nf_conntrack_l4proto nf_conntrack_l4proto_tcp6; | |
| 95 | −extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp4; | |
| 96 | −extern struct nf_conntrack_l4proto nf_conntrack_l4proto_udp6; | |
| 93 | +/* Existing built-in generic protocol */ | |
| 97 | 94 | extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; |
| 98 | 95 | |
| 99 | 96 | #define MAX_NF_CT_PROTO 256 |
| @@ -101,11 +98,6 @@ extern struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; · 1 unmodified line | ||
| 101 | 98 | extern struct nf_conntrack_l4proto * |
| 102 | 99 | __nf_ct_l4proto_find(u_int16_t l3proto, u_int8_t l4proto); |
| 103 | 100 | |
| 104 | −extern struct nf_conntrack_l4proto * | |
| 105 | −nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t protocol); | |
| 106 | − | |
| 107 | −extern void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p); | |
| 108 | − | |
| 109 | 101 | /* Protocol registration. */ |
| 110 | 102 | extern int nf_conntrack_l4proto_register(struct nf_conntrack_l4proto *proto); |
| 111 | 103 | extern void nf_conntrack_l4proto_unregister(struct nf_conntrack_l4proto *proto); |
| @@ -1,6 +1,8 @@ | ||
| 1 | 1 | #ifndef _NF_LOG_H |
| 2 | 2 | #define _NF_LOG_H |
| 3 | 3 | |
| 4 | +#include <linux/netfilter.h> | |
| 5 | + | |
| 4 | 6 | /* those NF_LOG_* defines and struct nf_loginfo are legacy definitios that will |
| 5 | 7 | * disappear once iptables is replaced with pkttables. Please DO NOT use them |
| 6 | 8 | * for any new code! */ |
| @@ -40,12 +42,15 @@ struct nf_logger { · 33 unmodified lines | ||
| 40 | 42 | struct module *me; |
| 41 | 43 | nf_logfn *logfn; |
| 42 | 44 | char *name; |
| 45 | + struct list_head list[NFPROTO_NUMPROTO]; | |
| 43 | 46 | }; |
| 44 | 47 | |
| 45 | 48 | /* Function to register/unregister log function. */ |
| 46 | −int nf_log_register(u_int8_t pf, const struct nf_logger *logger); | |
| 47 | −void nf_log_unregister(const struct nf_logger *logger); | |
| 48 | −void nf_log_unregister_pf(u_int8_t pf); | |
| 49 | +int nf_log_register(u_int8_t pf, struct nf_logger *logger); | |
| 50 | +void nf_log_unregister(struct nf_logger *logger); | |
| 51 | + | |
| 52 | +int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger); | |
| 53 | +void nf_log_unbind_pf(u_int8_t pf); | |
| 49 | 54 | |
| 50 | 55 | /* Calls the registered backend logging function */ |
| 51 | 56 | void nf_log_packet(u_int8_t pf, |
| @@ -46,7 +46,6 @@ static struct ebt_table broute_table = · 45 unmodified lines | ||
| 46 | 46 | .name = "broute", |
| 47 | 47 | .table = &initial_table, |
| 48 | 48 | .valid_hooks = 1 << NF_BR_BROUTING, |
| 49 | − .lock = __RW_LOCK_UNLOCKED(broute_table.lock), | |
| 50 | 49 | .check = check, |
| 51 | 50 | .me = THIS_MODULE, |
| 52 | 51 | }; |
| @@ -55,7 +55,6 @@ static struct ebt_table frame_filter = · 54 unmodified lines | ||
| 55 | 55 | .name = "filter", |
| 56 | 56 | .table = &initial_table, |
| 57 | 57 | .valid_hooks = FILTER_VALID_HOOKS, |
| 58 | − .lock = __RW_LOCK_UNLOCKED(frame_filter.lock), | |
| 59 | 58 | .check = check, |
| 60 | 59 | .me = THIS_MODULE, |
| 61 | 60 | }; |
| @@ -55,7 +55,6 @@ static struct ebt_table frame_nat = · 54 unmodified lines | ||
| 55 | 55 | .name = "nat", |
| 56 | 56 | .table = &initial_table, |
| 57 | 57 | .valid_hooks = NAT_VALID_HOOKS, |
| 58 | − .lock = __RW_LOCK_UNLOCKED(frame_nat.lock), | |
| 59 | 58 | .check = check, |
| 60 | 59 | .me = THIS_MODULE, |
| 61 | 60 | }; |
| @@ -31,7 +31,7 @@ config NF_CONNTRACK_PROC_COMPAT · 30 unmodified lines | ||
| 31 | 31 | default y |
| 32 | 32 | help |
| 33 | 33 | This option enables /proc and sysctl compatibility with the old |
| 34 | − layer 3 dependant connection tracking. This is needed to keep | |
| 34 | + layer 3 dependent connection tracking. This is needed to keep | |
| 35 | 35 | old programs that have not been adapted to the new names working. |
| 36 | 36 | |
| 37 | 37 | If unsure, say Y. |
| @@ -95,11 +95,11 @@ config IP_NF_MATCH_ECN · 57 unmodified lines | ||
| 95 | 95 | config IP_NF_MATCH_TTL |
| 96 | 96 | tristate '"ttl" match support' |
| 97 | 97 | depends on NETFILTER_ADVANCED |
| 98 | − help | |
| 99 | − This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user | |
| 100 | − to match packets by their TTL value. | |
| 101 | − | |
| 102 | − To compile it as a module, choose M here. If unsure, say N. | |
| 98 | + select NETFILTER_XT_MATCH_HL | |
| 99 | + ---help--- | |
| 100 | + This is a backwards-compat option for the user's convenience | |
| 101 | + (e.g. when running oldconfig). It selects | |
| 102 | + CONFIG_NETFILTER_XT_MATCH_HL. | |
| 103 | 103 | |
| 104 | 104 | # `filter', generic and specific targets |
| 105 | 105 | config IP_NF_FILTER |
| @@ -323,19 +323,13 @@ config IP_NF_TARGET_ECN · 217 unmodified lines | ||
| 323 | 323 | To compile it as a module, choose M here. If unsure, say N. |
| 324 | 324 | |
| 325 | 325 | config IP_NF_TARGET_TTL |
| 326 | − tristate 'TTL target support' | |
| 327 | − depends on IP_NF_MANGLE | |
| 326 | + tristate '"TTL" target support' | |
| 328 | 327 | depends on NETFILTER_ADVANCED |
| 329 | − help | |
| 330 | − This option adds a `TTL' target, which enables the user to modify | |
| 331 | − the TTL value of the IP header. | |
| 332 | − | |
| 333 | − While it is safe to decrement/lower the TTL, this target also enables | |
| 334 | − functionality to increment and set the TTL value of the IP header to | |
| 335 | − arbitrary values. This is EXTREMELY DANGEROUS since you can easily | |
| 336 | − create immortal packets that loop forever on the network. | |
| 337 | − | |
| 338 | − To compile it as a module, choose M here. If unsure, say N. | |
| 328 | + select NETFILTER_XT_TARGET_HL | |
| 329 | + ---help--- | |
| 330 | + This is a backwards-compat option for the user's convenience | |
| 331 | + (e.g. when running oldconfig). It selects | |
| 332 | + CONFIG_NETFILTER_XT_TARGET_HL. | |
| 339 | 333 | |
| 340 | 334 | # raw + specific targets |
| 341 | 335 | config IP_NF_RAW |
| @@ -51,7 +51,6 @@ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o · 50 unmodified lines | ||
| 51 | 51 | obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o |
| 52 | 52 | obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o |
| 53 | 53 | obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o |
| 54 | −obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o | |
| 55 | 54 | |
| 56 | 55 | # targets |
| 57 | 56 | obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o |
| @@ -61,7 +60,6 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o · 3 unmodified lines | ||
| 61 | 60 | obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o |
| 62 | 61 | obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o |
| 63 | 62 | obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o |
| 64 | −obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o | |
| 65 | 63 | obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o |
| 66 | 64 | |
| 67 | 65 | # generic ARP tables |
| @@ -73,6 +73,36 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap, · 72 unmodified lines | ||
| 73 | 73 | return (ret != 0); |
| 74 | 74 | } |
| 75 | 75 | |
| 76 | +/* | |
| 77 | + * Unfortunatly, _b and _mask are not aligned to an int (or long int) | |
| 78 | + * Some arches dont care, unrolling the loop is a win on them. | |
| 79 | + */ | |
| 80 | +static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) | |
| 81 | +{ | |
| 82 | +#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS | |
| 83 | + const unsigned long *a = (const unsigned long *)_a; | |
| 84 | + const unsigned long *b = (const unsigned long *)_b; | |
| 85 | + const unsigned long *mask = (const unsigned long *)_mask; | |
| 86 | + unsigned long ret; | |
| 87 | + | |
| 88 | + ret = (a[0] ^ b[0]) & mask[0]; | |
| 89 | + if (IFNAMSIZ > sizeof(unsigned long)) | |
| 90 | + ret |= (a[1] ^ b[1]) & mask[1]; | |
| 91 | + if (IFNAMSIZ > 2 * sizeof(unsigned long)) | |
| 92 | + ret |= (a[2] ^ b[2]) & mask[2]; | |
| 93 | + if (IFNAMSIZ > 3 * sizeof(unsigned long)) | |
| 94 | + ret |= (a[3] ^ b[3]) & mask[3]; | |
| 95 | + BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | |
| 96 | +#else | |
| 97 | + unsigned long ret = 0; | |
| 98 | + int i; | |
| 99 | + | |
| 100 | + for (i = 0; i < IFNAMSIZ; i++) | |
| 101 | + ret |= (_a[i] ^ _b[i]) & _mask[i]; | |
| 102 | +#endif | |
| 103 | + return ret; | |
| 104 | +} | |
| 105 | + | |
| 76 | 106 | /* Returns whether packet matches rule or not. */ |
| 77 | 107 | static inline int arp_packet_match(const struct arphdr *arphdr, |
| 78 | 108 | struct net_device *dev, |
| @@ -83,7 +113,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr, · 4 unmodified lines | ||
| 83 | 113 | const char *arpptr = (char *)(arphdr + 1); |
| 84 | 114 | const char *src_devaddr, *tgt_devaddr; |
| 85 | 115 | __be32 src_ipaddr, tgt_ipaddr; |
| 86 | − int i, ret; | |
| 116 | + long ret; | |
| 87 | 117 | |
| 88 | 118 | #define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg))) |
| 89 | 119 | |
| @@ -156,10 +186,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr, · 66 unmodified lines | ||
| 156 | 186 | } |
| 157 | 187 | |
| 158 | 188 | /* Look for ifname matches. */ |
| 159 | − for (i = 0, ret = 0; i < IFNAMSIZ; i++) { | |
| 160 | − ret |= (indev[i] ^ arpinfo->iniface[i]) | |
| 161 | − & arpinfo->iniface_mask[i]; | |
| 162 | − } | |
| 189 | + ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask); | |
| 163 | 190 | |
| 164 | 191 | if (FWINV(ret != 0, ARPT_INV_VIA_IN)) { |
| 165 | 192 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
| @@ -168,10 +195,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr, · 2 unmodified lines | ||
| 168 | 195 | return 0; |
| 169 | 196 | } |
| 170 | 197 | |
| 171 | − for (i = 0, ret = 0; i < IFNAMSIZ; i++) { | |
| 172 | − ret |= (outdev[i] ^ arpinfo->outiface[i]) | |
| 173 | − & arpinfo->outiface_mask[i]; | |
| 174 | − } | |
| 198 | + ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask); | |
| 175 | 199 | |
| 176 | 200 | if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) { |
| 177 | 201 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
| @@ -221,7 +245,7 @@ unsigned int arpt_do_table(struct sk_buff *skb, · 43 unmodified lines | ||
| 221 | 245 | const struct net_device *out, |
| 222 | 246 | struct xt_table *table) |
| 223 | 247 | { |
| 224 | − static const char nulldevname[IFNAMSIZ]; | |
| 248 | + static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); | |
| 225 | 249 | unsigned int verdict = NF_DROP; |
| 226 | 250 | const struct arphdr *arp; |
| 227 | 251 | bool hotdrop = false; |
| @@ -237,9 +261,10 @@ unsigned int arpt_do_table(struct sk_buff *skb, · 9 unmodified lines | ||
| 237 | 261 | indev = in ? in->name : nulldevname; |
| 238 | 262 | outdev = out ? out->name : nulldevname; |
| 239 | 263 | |
| 240 | − read_lock_bh(&table->lock); | |
| 241 | − private = table->private; | |
| 242 | − table_base = (void *)private->entries[smp_processor_id()]; | |
| 264 | + rcu_read_lock(); | |
| 265 | + private = rcu_dereference(table->private); | |
| 266 | + table_base = rcu_dereference(private->entries[smp_processor_id()]); | |
| 267 | + | |
| 243 | 268 | e = get_entry(table_base, private->hook_entry[hook]); |
| 244 | 269 | back = get_entry(table_base, private->underflow[hook]); |
| 245 | 270 | |
| @@ -311,7 +336,8 @@ unsigned int arpt_do_table(struct sk_buff *skb, · 65 unmodified lines | ||
| 311 | 336 | e = (void *)e + e->next_offset; |
| 312 | 337 | } |
| 313 | 338 | } while (!hotdrop); |
| 314 | − read_unlock_bh(&table->lock); | |
| 339 | + | |
| 340 | + rcu_read_unlock(); | |
| 315 | 341 | |
| 316 | 342 | if (hotdrop) |
| 317 | 343 | return NF_DROP; |
| @@ -714,11 +740,65 @@ static void get_counters(const struct xt_table_info *t, · 396 unmodified lines | ||
| 714 | 740 | } |
| 715 | 741 | } |
| 716 | 742 | |
| 717 | −static inline struct xt_counters *alloc_counters(struct xt_table *table) | |
| 743 | + | |
| 744 | +/* We're lazy, and add to the first CPU; overflow works its fey magic | |
| 745 | + * and everything is OK. */ | |
| 746 | +static int | |
| 747 | +add_counter_to_entry(struct arpt_entry *e, | |
| 748 | + const struct xt_counters addme[], | |
| 749 | + unsigned int *i) | |
| 750 | +{ | |
| 751 | + ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | |
| 752 | + | |
| 753 | + (*i)++; | |
| 754 | + return 0; | |
| 755 | +} | |
| 756 | + | |
| 757 | +/* Take values from counters and add them back onto the current cpu */ | |
| 758 | +static void put_counters(struct xt_table_info *t, | |
| 759 | + const struct xt_counters counters[]) | |
| 760 | +{ | |
| 761 | + unsigned int i, cpu; | |
| 762 | + | |
| 763 | + local_bh_disable(); | |
| 764 | + cpu = smp_processor_id(); | |
| 765 | + i = 0; | |
| 766 | + ARPT_ENTRY_ITERATE(t->entries[cpu], | |
| 767 | + t->size, | |
| 768 | + add_counter_to_entry, | |
| 769 | + counters, | |
| 770 | + &i); | |
| 771 | + local_bh_enable(); | |
| 772 | +} | |
| 773 | + | |
| 774 | +static inline int | |
| 775 | +zero_entry_counter(struct arpt_entry *e, void *arg) | |
| 776 | +{ | |
| 777 | + e->counters.bcnt = 0; | |
| 778 | + e->counters.pcnt = 0; | |
| 779 | + return 0; | |
| 780 | +} | |
| 781 | + | |
| 782 | +static void | |
| 783 | +clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info) | |
| 784 | +{ | |
| 785 | + unsigned int cpu; | |
| 786 | + const void *loc_cpu_entry = info->entries[raw_smp_processor_id()]; | |
| 787 | + | |
| 788 | + memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | |
| 789 | + for_each_possible_cpu(cpu) { | |
| 790 | + memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size); | |
| 791 | + ARPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size, | |
| 792 | + zero_entry_counter, NULL); | |
| 793 | + } | |
| 794 | +} | |
| 795 | + | |
| 796 | +static struct xt_counters *alloc_counters(struct xt_table *table) | |
| 718 | 797 | { |
| 719 | 798 | unsigned int countersize; |
| 720 | 799 | struct xt_counters *counters; |
| 721 | − const struct xt_table_info *private = table->private; | |
| 800 | + struct xt_table_info *private = table->private; | |
| 801 | + struct xt_table_info *info; | |
| 722 | 802 | |
| 723 | 803 | /* We need atomic snapshot of counters: rest doesn't change |
| 724 | 804 | * (other than comefrom, which userspace doesn't care |
| @@ -728,14 +808,30 @@ static inline struct xt_counters *alloc_counters(struct xt_table *table) · 3 unmodified lines | ||
| 728 | 808 | counters = vmalloc_node(countersize, numa_node_id()); |
| 729 | 809 | |
| 730 | 810 | if (counters == NULL) |
| 731 | − return ERR_PTR(-ENOMEM); | |
| 811 | + goto nomem; | |
| 812 | + | |
| 813 | + info = xt_alloc_table_info(private->size); | |
| 814 | + if (!info) | |
| 815 | + goto free_counters; | |
| 816 | + | |
| 817 | + clone_counters(info, private); | |
| 818 | + | |
| 819 | + mutex_lock(&table->lock); | |
| 820 | + xt_table_entry_swap_rcu(private, info); | |
| 821 | + synchronize_net(); /* Wait until smoke has cleared */ | |
| 822 | + | |
| 823 | + get_counters(info, counters); | |
| 824 | + put_counters(private, counters); | |
| 825 | + mutex_unlock(&table->lock); | |
| 732 | 826 | |
| 733 | − /* First, sum counters... */ | |
| 734 | − write_lock_bh(&table->lock); | |
| 735 | − get_counters(private, counters); | |
| 736 | − write_unlock_bh(&table->lock); | |
| 827 | + xt_free_table_info(info); | |
| 737 | 828 | |
| 738 | 829 | return counters; |
| 830 | + | |
| 831 | + free_counters: | |
| 832 | + vfree(counters); | |
| 833 | + nomem: | |
| 834 | + return ERR_PTR(-ENOMEM); | |
| 739 | 835 | } |
| 740 | 836 | |
| 741 | 837 | static int copy_entries_to_user(unsigned int total_size, |
| @@ -1075,20 +1171,6 @@ static int do_replace(struct net *net, void __user *user, unsigned int len) · 333 unmodified lines | ||
| 1075 | 1171 | return ret; |
| 1076 | 1172 | } |
| 1077 | 1173 | |
| 1078 | −/* We're lazy, and add to the first CPU; overflow works its fey magic | |
| 1079 | − * and everything is OK. | |
| 1080 | − */ | |
| 1081 | −static inline int add_counter_to_entry(struct arpt_entry *e, | |
| 1082 | − const struct xt_counters addme[], | |
| 1083 | − unsigned int *i) | |
| 1084 | −{ | |
| 1085 | − | |
| 1086 | − ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | |
| 1087 | − | |
| 1088 | − (*i)++; | |
| 1089 | − return 0; | |
| 1090 | −} | |
| 1091 | − | |
| 1092 | 1174 | static int do_add_counters(struct net *net, void __user *user, unsigned int len, |
| 1093 | 1175 | int compat) |
| 1094 | 1176 | { |
| @@ -1148,13 +1230,14 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len, · 53 unmodified lines | ||
| 1148 | 1230 | goto free; |
| 1149 | 1231 | } |
| 1150 | 1232 | |
| 1151 | − write_lock_bh(&t->lock); | |
| 1233 | + mutex_lock(&t->lock); | |
| 1152 | 1234 | private = t->private; |
| 1153 | 1235 | if (private->number != num_counters) { |
| 1154 | 1236 | ret = -EINVAL; |
| 1155 | 1237 | goto unlock_up_free; |
| 1156 | 1238 | } |
| 1157 | 1239 | |
| 1240 | + preempt_disable(); | |
| 1158 | 1241 | i = 0; |
| 1159 | 1242 | /* Choose the copy that is on our node */ |
| 1160 | 1243 | loc_cpu_entry = private->entries[smp_processor_id()]; |
| @@ -1163,8 +1246,10 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len, · 2 unmodified lines | ||
| 1163 | 1246 | add_counter_to_entry, |
| 1164 | 1247 | paddc, |
| 1165 | 1248 | &i); |
| 1249 | + preempt_enable(); | |
| 1166 | 1250 | unlock_up_free: |
| 1167 | − write_unlock_bh(&t->lock); | |
| 1251 | + mutex_unlock(&t->lock); | |
| 1252 | + | |
| 1168 | 1253 | xt_table_unlock(t); |
| 1169 | 1254 | module_put(t->me); |
| 1170 | 1255 | free: |
| @@ -48,8 +48,6 @@ static struct · 47 unmodified lines | ||
| 48 | 48 | static struct xt_table packet_filter = { |
| 49 | 49 | .name = "filter", |
| 50 | 50 | .valid_hooks = FILTER_VALID_HOOKS, |
| 51 | − .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), | |
| 52 | − .private = NULL, | |
| 53 | 51 | .me = THIS_MODULE, |
| 54 | 52 | .af = NFPROTO_ARP, |
| 55 | 53 | }; |
| @@ -24,6 +24,7 @@ · 23 unmodified lines | ||
| 24 | 24 | #include <linux/proc_fs.h> |
| 25 | 25 | #include <linux/seq_file.h> |
| 26 | 26 | #include <linux/security.h> |
| 27 | +#include <linux/net.h> | |
| 27 | 28 | #include <linux/mutex.h> |
| 28 | 29 | #include <net/net_namespace.h> |
| 29 | 30 | #include <net/sock.h> |
| @@ -640,6 +641,7 @@ static void __exit ip_queue_fini(void) · 610 unmodified lines | ||
| 640 | 641 | MODULE_DESCRIPTION("IPv4 packet queue handler"); |
| 641 | 642 | MODULE_AUTHOR("James Morris <jmorris@intercode.com.au>"); |
| 642 | 643 | MODULE_LICENSE("GPL"); |
| 644 | +MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_FIREWALL); | |
| 643 | 645 | |
| 644 | 646 | module_init(ip_queue_init); |
| 645 | 647 | module_exit(ip_queue_fini); |
| @@ -74,6 +74,25 @@ do { \ · 73 unmodified lines | ||
| 74 | 74 | |
| 75 | 75 | Hence the start of any table is given by get_table() below. */ |
| 76 | 76 | |
| 77 | +static unsigned long ifname_compare(const char *_a, const char *_b, | |
| 78 | + const unsigned char *_mask) | |
| 79 | +{ | |
| 80 | + const unsigned long *a = (const unsigned long *)_a; | |
| 81 | + const unsigned long *b = (const unsigned long *)_b; | |
| 82 | + const unsigned long *mask = (const unsigned long *)_mask; | |
| 83 | + unsigned long ret; | |
| 84 | + | |
| 85 | + ret = (a[0] ^ b[0]) & mask[0]; | |
| 86 | + if (IFNAMSIZ > sizeof(unsigned long)) | |
| 87 | + ret |= (a[1] ^ b[1]) & mask[1]; | |
| 88 | + if (IFNAMSIZ > 2 * sizeof(unsigned long)) | |
| 89 | + ret |= (a[2] ^ b[2]) & mask[2]; | |
| 90 | + if (IFNAMSIZ > 3 * sizeof(unsigned long)) | |
| 91 | + ret |= (a[3] ^ b[3]) & mask[3]; | |
| 92 | + BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | |
| 93 | + return ret; | |
| 94 | +} | |
| 95 | + | |
| 77 | 96 | /* Returns whether matches rule or not. */ |
| 78 | 97 | /* Performance critical - called for every packet */ |
| 79 | 98 | static inline bool |
| @@ -83,7 +102,6 @@ ip_packet_match(const struct iphdr *ip, · 3 unmodified lines | ||
| 83 | 102 | const struct ipt_ip *ipinfo, |
| 84 | 103 | int isfrag) |
| 85 | 104 | { |
| 86 | − size_t i; | |
| 87 | 105 | unsigned long ret; |
| 88 | 106 | |
| 89 | 107 | #define FWINV(bool, invflg) ((bool) ^ !!(ipinfo->invflags & (invflg))) |
| @@ -103,12 +121,7 @@ ip_packet_match(const struct iphdr *ip, · 13 unmodified lines | ||
| 103 | 121 | return false; |
| 104 | 122 | } |
| 105 | 123 | |
| 106 | − /* Look for ifname matches; this should unroll nicely. */ | |
| 107 | − for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | |
| 108 | − ret |= (((const unsigned long *)indev)[i] | |
| 109 | − ^ ((const unsigned long *)ipinfo->iniface)[i]) | |
| 110 | − & ((const unsigned long *)ipinfo->iniface_mask)[i]; | |
| 111 | − } | |
| 124 | + ret = ifname_compare(indev, ipinfo->iniface, ipinfo->iniface_mask); | |
| 112 | 125 | |
| 113 | 126 | if (FWINV(ret != 0, IPT_INV_VIA_IN)) { |
| 114 | 127 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
| @@ -117,11 +130,7 @@ ip_packet_match(const struct iphdr *ip, · 2 unmodified lines | ||
| 117 | 130 | return false; |
| 118 | 131 | } |
| 119 | 132 | |
| 120 | − for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | |
| 121 | − ret |= (((const unsigned long *)outdev)[i] | |
| 122 | − ^ ((const unsigned long *)ipinfo->outiface)[i]) | |
| 123 | − & ((const unsigned long *)ipinfo->outiface_mask)[i]; | |
| 124 | − } | |
| 133 | + ret = ifname_compare(outdev, ipinfo->outiface, ipinfo->outiface_mask); | |
| 125 | 134 | |
| 126 | 135 | if (FWINV(ret != 0, IPT_INV_VIA_OUT)) { |
| 127 | 136 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
| @@ -347,10 +356,12 @@ ipt_do_table(struct sk_buff *skb, · 219 unmodified lines | ||
| 347 | 356 | mtpar.family = tgpar.family = NFPROTO_IPV4; |
| 348 | 357 | tgpar.hooknum = hook; |
| 349 | 358 | |
| 350 | − read_lock_bh(&table->lock); | |
| 351 | 359 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); |
| 352 | − private = table->private; | |
| 353 | − table_base = (void *)private->entries[smp_processor_id()]; | |
| 360 | + | |
| 361 | + rcu_read_lock(); | |
| 362 | + private = rcu_dereference(table->private); | |
| 363 | + table_base = rcu_dereference(private->entries[smp_processor_id()]); | |
| 364 | + | |
| 354 | 365 | e = get_entry(table_base, private->hook_entry[hook]); |
| 355 | 366 | |
| 356 | 367 | /* For return from builtin chain */ |
| @@ -445,7 +456,7 @@ ipt_do_table(struct sk_buff *skb, · 88 unmodified lines | ||
| 445 | 456 | } |
| 446 | 457 | } while (!hotdrop); |
| 447 | 458 | |
| 448 | − read_unlock_bh(&table->lock); | |
| 459 | + rcu_read_unlock(); | |
| 449 | 460 | |
| 450 | 461 | #ifdef DEBUG_ALLOW_ALL |
| 451 | 462 | return NF_ACCEPT; |
| @@ -924,13 +935,68 @@ get_counters(const struct xt_table_info *t, · 472 unmodified lines | ||
| 924 | 935 | counters, |
| 925 | 936 | &i); |
| 926 | 937 | } |
| 938 | + | |
| 939 | +} | |
| 940 | + | |
| 941 | +/* We're lazy, and add to the first CPU; overflow works its fey magic | |
| 942 | + * and everything is OK. */ | |
| 943 | +static int | |
| 944 | +add_counter_to_entry(struct ipt_entry *e, | |
| 945 | + const struct xt_counters addme[], | |
| 946 | + unsigned int *i) | |
| 947 | +{ | |
| 948 | + ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | |
| 949 | + | |
| 950 | + (*i)++; | |
| 951 | + return 0; | |
| 952 | +} | |
| 953 | + | |
| 954 | +/* Take values from counters and add them back onto the current cpu */ | |
| 955 | +static void put_counters(struct xt_table_info *t, | |
| 956 | + const struct xt_counters counters[]) | |
| 957 | +{ | |
| 958 | + unsigned int i, cpu; | |
| 959 | + | |
| 960 | + local_bh_disable(); | |
| 961 | + cpu = smp_processor_id(); | |
| 962 | + i = 0; | |
| 963 | + IPT_ENTRY_ITERATE(t->entries[cpu], | |
| 964 | + t->size, | |
| 965 | + add_counter_to_entry, | |
| 966 | + counters, | |
| 967 | + &i); | |
| 968 | + local_bh_enable(); | |
| 969 | +} | |
| 970 | + | |
| 971 | + | |
| 972 | +static inline int | |
| 973 | +zero_entry_counter(struct ipt_entry *e, void *arg) | |
| 974 | +{ | |
| 975 | + e->counters.bcnt = 0; | |
| 976 | + e->counters.pcnt = 0; | |
| 977 | + return 0; | |
| 978 | +} | |
| 979 | + | |
| 980 | +static void | |
| 981 | +clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info) | |
| 982 | +{ | |
| 983 | + unsigned int cpu; | |
| 984 | + const void *loc_cpu_entry = info->entries[raw_smp_processor_id()]; | |
| 985 | + | |
| 986 | + memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | |
| 987 | + for_each_possible_cpu(cpu) { | |
| 988 | + memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size); | |
| 989 | + IPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size, | |
| 990 | + zero_entry_counter, NULL); | |
| 991 | + } | |
| 927 | 992 | } |
| 928 | 993 | |
| 929 | 994 | static struct xt_counters * alloc_counters(struct xt_table *table) |
| 930 | 995 | { |
| 931 | 996 | unsigned int countersize; |
| 932 | 997 | struct xt_counters *counters; |
| 933 | − const struct xt_table_info *private = table->private; | |
| 998 | + struct xt_table_info *private = table->private; | |
| 999 | + struct xt_table_info *info; | |
| 934 | 1000 | |
| 935 | 1001 | /* We need atomic snapshot of counters: rest doesn't change |
| 936 | 1002 | (other than comefrom, which userspace doesn't care |
| @@ -939,14 +1005,30 @@ static struct xt_counters * alloc_counters(struct xt_table *table) · 2 unmodified lines | ||
| 939 | 1005 | counters = vmalloc_node(countersize, numa_node_id()); |
| 940 | 1006 | |
| 941 | 1007 | if (counters == NULL) |
| 942 | − return ERR_PTR(-ENOMEM); | |
| 1008 | + goto nomem; | |
| 1009 | + | |
| 1010 | + info = xt_alloc_table_info(private->size); | |
| 1011 | + if (!info) | |
| 1012 | + goto free_counters; | |
| 943 | 1013 | |
| 944 | − /* First, sum counters... */ | |
| 945 | − write_lock_bh(&table->lock); | |
| 946 | − get_counters(private, counters); | |
| 947 | − write_unlock_bh(&table->lock); | |
| 1014 | + clone_counters(info, private); | |
| 1015 | + | |
| 1016 | + mutex_lock(&table->lock); | |
| 1017 | + xt_table_entry_swap_rcu(private, info); | |
| 1018 | + synchronize_net(); /* Wait until smoke has cleared */ | |
| 1019 | + | |
| 1020 | + get_counters(info, counters); | |
| 1021 | + put_counters(private, counters); | |
| 1022 | + mutex_unlock(&table->lock); | |
| 1023 | + | |
| 1024 | + xt_free_table_info(info); | |
| 948 | 1025 | |
| 949 | 1026 | return counters; |
| 1027 | + | |
| 1028 | + free_counters: | |
| 1029 | + vfree(counters); | |
| 1030 | + nomem: | |
| 1031 | + return ERR_PTR(-ENOMEM); | |
| 950 | 1032 | } |
| 951 | 1033 | |
| 952 | 1034 | static int |
| @@ -1312,27 +1394,6 @@ do_replace(struct net *net, void __user *user, unsigned int len) · 359 unmodified lines | ||
| 1312 | 1394 | return ret; |
| 1313 | 1395 | } |
| 1314 | 1396 | |
| 1315 | −/* We're lazy, and add to the first CPU; overflow works its fey magic | |
| 1316 | − * and everything is OK. */ | |
| 1317 | −static int | |
| 1318 | −add_counter_to_entry(struct ipt_entry *e, | |
| 1319 | − const struct xt_counters addme[], | |
| 1320 | − unsigned int *i) | |
| 1321 | −{ | |
| 1322 | −#if 0 | |
| 1323 | − duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n", | |
| 1324 | − *i, | |
| 1325 | − (long unsigned int)e->counters.pcnt, | |
| 1326 | − (long unsigned int)e->counters.bcnt, | |
| 1327 | − (long unsigned int)addme[*i].pcnt, | |
| 1328 | − (long unsigned int)addme[*i].bcnt); | |
| 1329 | −#endif | |
| 1330 | − | |
| 1331 | − ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | |
| 1332 | − | |
| 1333 | − (*i)++; | |
| 1334 | − return 0; | |
| 1335 | −} | |
| 1336 | 1397 | |
| 1337 | 1398 | static int |
| 1338 | 1399 | do_add_counters(struct net *net, void __user *user, unsigned int len, int compat) |
| @@ -1393,13 +1454,14 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat · 54 unmodified lines | ||
| 1393 | 1454 | goto free; |
| 1394 | 1455 | } |
| 1395 | 1456 | |
| 1396 | − write_lock_bh(&t->lock); | |
| 1457 | + mutex_lock(&t->lock); | |
| 1397 | 1458 | private = t->private; |
| 1398 | 1459 | if (private->number != num_counters) { |
| 1399 | 1460 | ret = -EINVAL; |
| 1400 | 1461 | goto unlock_up_free; |
| 1401 | 1462 | } |
| 1402 | 1463 | |
| 1464 | + preempt_disable(); | |
| 1403 | 1465 | i = 0; |
| 1404 | 1466 | /* Choose the copy that is on our node */ |
| 1405 | 1467 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| @@ -1408,8 +1470,9 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat · 2 unmodified lines | ||
| 1408 | 1470 | add_counter_to_entry, |
| 1409 | 1471 | paddc, |
| 1410 | 1472 | &i); |
| 1473 | + preempt_enable(); | |
| 1411 | 1474 | unlock_up_free: |
| 1412 | − write_unlock_bh(&t->lock); | |
| 1475 | + mutex_unlock(&t->lock); | |
| 1413 | 1476 | xt_table_unlock(t); |
| 1414 | 1477 | module_put(t->me); |
| 1415 | 1478 | free: |
| @@ -464,7 +464,7 @@ static struct xt_target log_tg_reg __read_mostly = { · 463 unmodified lines | ||
| 464 | 464 | .me = THIS_MODULE, |
| 465 | 465 | }; |
| 466 | 466 | |
| 467 | −static const struct nf_logger ipt_log_logger ={ | |
| 467 | +static struct nf_logger ipt_log_logger __read_mostly = { | |
| 468 | 468 | .name = "ipt_LOG", |
| 469 | 469 | .logfn = &ipt_log_packet, |
| 470 | 470 | .me = THIS_MODULE, |
| @@ -1,97 +0,0 @@ | ||
| 1 | −/* TTL modification target for IP tables | |
| 2 | − * (C) 2000,2005 by Harald Welte <laforge@netfilter.org> | |
| 3 | − * | |
| 4 | − * This program is free software; you can redistribute it and/or modify | |
| 5 | − * it under the terms of the GNU General Public License version 2 as | |
| 6 | − * published by the Free Software Foundation. | |
| 7 | − * | |
| 8 | − */ | |
| 9 | − | |
| 10 | −#include <linux/module.h> | |
| 11 | −#include <linux/skbuff.h> | |
| 12 | −#include <linux/ip.h> | |
| 13 | −#include <net/checksum.h> | |
| 14 | − | |
| 15 | −#include <linux/netfilter/x_tables.h> | |
| 16 | −#include <linux/netfilter_ipv4/ipt_TTL.h> | |
| 17 | − | |
| 18 | −MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | |
| 19 | −MODULE_DESCRIPTION("Xtables: IPv4 TTL field modification target"); | |
| 20 | −MODULE_LICENSE("GPL"); | |
| 21 | − | |
| 22 | −static unsigned int | |
| 23 | −ttl_tg(struct sk_buff *skb, const struct xt_target_param *par) | |
| 24 | −{ | |
| 25 | − struct iphdr *iph; | |
| 26 | − const struct ipt_TTL_info *info = par->targinfo; | |
| 27 | − int new_ttl; | |
| 28 | − | |
| 29 | − if (!skb_make_writable(skb, skb->len)) | |
| 30 | − return NF_DROP; | |
| 31 | − | |
| 32 | − iph = ip_hdr(skb); | |
| 33 | − | |
| 34 | − switch (info->mode) { | |
| 35 | − case IPT_TTL_SET: | |
| 36 | − new_ttl = info->ttl; | |
| 37 | − break; | |
| 38 | − case IPT_TTL_INC: | |
| 39 | − new_ttl = iph->ttl + info->ttl; | |
| 40 | − if (new_ttl > 255) | |
| 41 | − new_ttl = 255; | |
| 42 | − break; | |
| 43 | − case IPT_TTL_DEC: | |
| 44 | − new_ttl = iph->ttl - info->ttl; | |
| 45 | − if (new_ttl < 0) | |
| 46 | − new_ttl = 0; | |
| 47 | − break; | |
| 48 | − default: | |
| 49 | − new_ttl = iph->ttl; | |
| 50 | − break; | |
| 51 | − } | |
| 52 | − | |
| 53 | − if (new_ttl != iph->ttl) { | |
| 54 | − csum_replace2(&iph->check, htons(iph->ttl << 8), | |
| 55 | − htons(new_ttl << 8)); | |
| 56 | − iph->ttl = new_ttl; | |
| 57 | − } | |
| 58 | − | |
| 59 | − return XT_CONTINUE; | |
| 60 | −} | |
| 61 | − | |
| 62 | −static bool ttl_tg_check(const struct xt_tgchk_param *par) | |
| 63 | −{ | |
| 64 | − const struct ipt_TTL_info *info = par->targinfo; | |
| 65 | − | |
| 66 | − if (info->mode > IPT_TTL_MAXMODE) { | |
| 67 | − printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", | |
| 68 | − info->mode); | |
| 69 | − return false; | |
| 70 | − } | |
| 71 | − if (info->mode != IPT_TTL_SET && info->ttl == 0) | |
| 72 | − return false; | |
| 73 | − return true; | |
| 74 | −} | |
| 75 | − | |
| 76 | −static struct xt_target ttl_tg_reg __read_mostly = { | |
| 77 | − .name = "TTL", | |
| 78 | − .family = NFPROTO_IPV4, | |
| 79 | − .target = ttl_tg, | |
| 80 | − .targetsize = sizeof(struct ipt_TTL_info), | |
| 81 | − .table = "mangle", | |
| 82 | − .checkentry = ttl_tg_check, | |
| 83 | − .me = THIS_MODULE, | |
| 84 | −}; | |
| 85 | − | |
| 86 | −static int __init ttl_tg_init(void) | |
| 87 | −{ | |
| 88 | − return xt_register_target(&ttl_tg_reg); | |
| 89 | −} | |
| 90 | − | |
| 91 | −static void __exit ttl_tg_exit(void) | |
| 92 | −{ | |
| 93 | − xt_unregister_target(&ttl_tg_reg); | |
| 94 | −} | |
| 95 | − | |
| 96 | −module_init(ttl_tg_init); | |
| 97 | −module_exit(ttl_tg_exit); | |
| @@ -379,7 +379,7 @@ static struct xt_target ulog_tg_reg __read_mostly = { · 378 unmodified lines | ||
| 379 | 379 | .me = THIS_MODULE, |
| 380 | 380 | }; |
| 381 | 381 | |
| 382 | −static struct nf_logger ipt_ulog_logger = { | |
| 382 | +static struct nf_logger ipt_ulog_logger __read_mostly = { | |
| 383 | 383 | .name = "ipt_ULOG", |
| 384 | 384 | .logfn = ipt_logfn, |
| 385 | 385 | .me = THIS_MODULE, |
| @@ -1,63 +0,0 @@ | ||
| 1 | −/* IP tables module for matching the value of the TTL | |
| 2 | − * | |
| 3 | − * (C) 2000,2001 by Harald Welte <laforge@netfilter.org> | |
| 4 | − * | |
| 5 | − * This program is free software; you can redistribute it and/or modify | |
| 6 | − * it under the terms of the GNU General Public License version 2 as | |
| 7 | − * published by the Free Software Foundation. | |
| 8 | − */ | |
| 9 | − | |
| 10 | −#include <linux/ip.h> | |
| 11 | −#include <linux/module.h> | |
| 12 | −#include <linux/skbuff.h> | |
| 13 | − | |
| 14 | −#include <linux/netfilter_ipv4/ipt_ttl.h> | |
| 15 | −#include <linux/netfilter/x_tables.h> | |
| 16 | − | |
| 17 | −MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | |
| 18 | −MODULE_DESCRIPTION("Xtables: IPv4 TTL field match"); | |
| 19 | −MODULE_LICENSE("GPL"); | |
| 20 | − | |
| 21 | −static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |
| 22 | −{ | |
| 23 | − const struct ipt_ttl_info *info = par->matchinfo; | |
| 24 | − const u8 ttl = ip_hdr(skb)->ttl; | |
| 25 | − | |
| 26 | − switch (info->mode) { | |
| 27 | − case IPT_TTL_EQ: | |
| 28 | − return ttl == info->ttl; | |
| 29 | − case IPT_TTL_NE: | |
| 30 | − return ttl != info->ttl; | |
| 31 | − case IPT_TTL_LT: | |
| 32 | − return ttl < info->ttl; | |
| 33 | − case IPT_TTL_GT: | |
| 34 | − return ttl > info->ttl; | |
| 35 | − default: | |
| 36 | − printk(KERN_WARNING "ipt_ttl: unknown mode %d\n", | |
| 37 | − info->mode); | |
| 38 | − return false; | |
| 39 | − } | |
| 40 | − | |
| 41 | − return false; | |
| 42 | −} | |
| 43 | − | |
| 44 | −static struct xt_match ttl_mt_reg __read_mostly = { | |
| 45 | − .name = "ttl", | |
| 46 | − .family = NFPROTO_IPV4, | |
| 47 | − .match = ttl_mt, | |
| 48 | − .matchsize = sizeof(struct ipt_ttl_info), | |
| 49 | − .me = THIS_MODULE, | |
| 50 | −}; | |
| 51 | − | |
| 52 | −static int __init ttl_mt_init(void) | |
| 53 | −{ | |
| 54 | − return xt_register_match(&ttl_mt_reg); | |
| 55 | −} | |
| 56 | − | |
| 57 | −static void __exit ttl_mt_exit(void) | |
| 58 | −{ | |
| 59 | − xt_unregister_match(&ttl_mt_reg); | |
| 60 | −} | |
| 61 | − | |
| 62 | −module_init(ttl_mt_init); | |
| 63 | −module_exit(ttl_mt_exit); | |
| @@ -56,7 +56,6 @@ static struct · 55 unmodified lines | ||
| 56 | 56 | static struct xt_table packet_filter = { |
| 57 | 57 | .name = "filter", |
| 58 | 58 | .valid_hooks = FILTER_VALID_HOOKS, |
| 59 | − .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), | |
| 60 | 59 | .me = THIS_MODULE, |
| 61 | 60 | .af = AF_INET, |
| 62 | 61 | }; |
| @@ -67,7 +67,6 @@ static struct · 66 unmodified lines | ||
| 67 | 67 | static struct xt_table packet_mangler = { |
| 68 | 68 | .name = "mangle", |
| 69 | 69 | .valid_hooks = MANGLE_VALID_HOOKS, |
| 70 | − .lock = __RW_LOCK_UNLOCKED(packet_mangler.lock), | |
| 71 | 70 | .me = THIS_MODULE, |
| 72 | 71 | .af = AF_INET, |
| 73 | 72 | }; |
| @@ -39,7 +39,6 @@ static struct · 38 unmodified lines | ||
| 39 | 39 | static struct xt_table packet_raw = { |
| 40 | 40 | .name = "raw", |
| 41 | 41 | .valid_hooks = RAW_VALID_HOOKS, |
| 42 | − .lock = __RW_LOCK_UNLOCKED(packet_raw.lock), | |
| 43 | 42 | .me = THIS_MODULE, |
| 44 | 43 | .af = AF_INET, |
| 45 | 44 | }; |
| @@ -60,7 +60,6 @@ static struct · 59 unmodified lines | ||
| 60 | 60 | static struct xt_table security_table = { |
| 61 | 61 | .name = "security", |
| 62 | 62 | .valid_hooks = SECURITY_VALID_HOOKS, |
| 63 | − .lock = __RW_LOCK_UNLOCKED(security_table.lock), | |
| 64 | 63 | .me = THIS_MODULE, |
| 65 | 64 | .af = AF_INET, |
| 66 | 65 | }; |
| @@ -120,8 +120,10 @@ static unsigned int ipv4_confirm(unsigned int hooknum, · 119 unmodified lines | ||
| 120 | 120 | typeof(nf_nat_seq_adjust_hook) seq_adjust; |
| 121 | 121 | |
| 122 | 122 | seq_adjust = rcu_dereference(nf_nat_seq_adjust_hook); |
| 123 | − if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) | |
| 123 | + if (!seq_adjust || !seq_adjust(skb, ct, ctinfo)) { | |
| 124 | + NF_CT_STAT_INC_ATOMIC(nf_ct_net(ct), drop); | |
| 124 | 125 | return NF_DROP; |
| 126 | + } | |
| 125 | 127 | } |
| 126 | 128 | out: |
| 127 | 129 | /* We've seen it coming out the other side: confirm it */ |
| @@ -61,7 +61,6 @@ static struct · 60 unmodified lines | ||
| 61 | 61 | static struct xt_table nat_table = { |
| 62 | 62 | .name = "nat", |
| 63 | 63 | .valid_hooks = NAT_VALID_HOOKS, |
| 64 | − .lock = __RW_LOCK_UNLOCKED(nat_table.lock), | |
| 65 | 64 | .me = THIS_MODULE, |
| 66 | 65 | .af = AF_INET, |
| 67 | 66 | }; |
| @@ -95,13 +95,13 @@ config IP6_NF_MATCH_OPTS · 94 unmodified lines | ||
| 95 | 95 | To compile it as a module, choose M here. If unsure, say N. |
| 96 | 96 | |
| 97 | 97 | config IP6_NF_MATCH_HL |
| 98 | − tristate '"hl" match support' | |
| 98 | + tristate '"hl" hoplimit match support' | |
| 99 | 99 | depends on NETFILTER_ADVANCED |
| 100 | − help | |
| 101 | − HL matching allows you to match packets based on the hop | |
| 102 | − limit of the packet. | |
| 103 | − | |
| 104 | − To compile it as a module, choose M here. If unsure, say N. | |
| 100 | + select NETFILTER_XT_MATCH_HL | |
| 101 | + ---help--- | |
| 102 | + This is a backwards-compat option for the user's convenience | |
| 103 | + (e.g. when running oldconfig). It selects | |
| 104 | + COFNIG_NETFILTER_XT_MATCH_HL. | |
| 105 | 105 | |
| 106 | 106 | config IP6_NF_MATCH_IPV6HEADER |
| 107 | 107 | tristate '"ipv6header" IPv6 Extension Headers Match' |
| @@ -130,6 +130,15 @@ config IP6_NF_MATCH_RT · 22 unmodified lines | ||
| 130 | 130 | To compile it as a module, choose M here. If unsure, say N. |
| 131 | 131 | |
| 132 | 132 | # The targets |
| 133 | +config IP6_NF_TARGET_HL | |
| 134 | + tristate '"HL" hoplimit target support' | |
| 135 | + depends on NETFILTER_ADVANCED | |
| 136 | + select NETFILTER_XT_TARGET_HL | |
| 137 | + ---help--- | |
| 138 | + This is a backwards-compat option for the user's convenience | |
| 139 | + (e.g. when running oldconfig). It selects | |
| 140 | + COFNIG_NETFILTER_XT_TARGET_HL. | |
| 141 | + | |
| 133 | 142 | config IP6_NF_TARGET_LOG |
| 134 | 143 | tristate "LOG target support" |
| 135 | 144 | default m if NETFILTER_ADVANCED=n |
| @@ -170,23 +179,6 @@ config IP6_NF_MANGLE · 34 unmodified lines | ||
| 170 | 179 | |
| 171 | 180 | To compile it as a module, choose M here. If unsure, say N. |
| 172 | 181 | |
| 173 | −config IP6_NF_TARGET_HL | |
| 174 | − tristate 'HL (hoplimit) target support' | |
| 175 | − depends on IP6_NF_MANGLE | |
| 176 | − depends on NETFILTER_ADVANCED | |
| 177 | − help | |
| 178 | − This option adds a `HL' target, which enables the user to decrement | |
| 179 | − the hoplimit value of the IPv6 header or set it to a given (lower) | |
| 180 | − value. | |
| 181 | − | |
| 182 | − While it is safe to decrement the hoplimit value, this option also | |
| 183 | − enables functionality to increment and set the hoplimit value of the | |
| 184 | − IPv6 header to arbitrary values. This is EXTREMELY DANGEROUS since | |
| 185 | − you can easily create immortal packets that loop forever on the | |
| 186 | − network. | |
| 187 | − | |
| 188 | − To compile it as a module, choose M here. If unsure, say N. | |
| 189 | − | |
| 190 | 182 | config IP6_NF_RAW |
| 191 | 183 | tristate 'raw table support (required for TRACE)' |
| 192 | 184 | depends on NETFILTER_ADVANCED |
| @@ -20,13 +20,11 @@ obj-$(CONFIG_NF_CONNTRACK_IPV6) += nf_conntrack_ipv6.o · 19 unmodified lines | ||
| 20 | 20 | obj-$(CONFIG_IP6_NF_MATCH_AH) += ip6t_ah.o |
| 21 | 21 | obj-$(CONFIG_IP6_NF_MATCH_EUI64) += ip6t_eui64.o |
| 22 | 22 | obj-$(CONFIG_IP6_NF_MATCH_FRAG) += ip6t_frag.o |
| 23 | −obj-$(CONFIG_IP6_NF_MATCH_HL) += ip6t_hl.o | |
| 24 | 23 | obj-$(CONFIG_IP6_NF_MATCH_IPV6HEADER) += ip6t_ipv6header.o |
| 25 | 24 | obj-$(CONFIG_IP6_NF_MATCH_MH) += ip6t_mh.o |
| 26 | 25 | obj-$(CONFIG_IP6_NF_MATCH_OPTS) += ip6t_hbh.o |
| 27 | 26 | obj-$(CONFIG_IP6_NF_MATCH_RT) += ip6t_rt.o |
| 28 | 27 | |
| 29 | 28 | # targets |
| 30 | −obj-$(CONFIG_IP6_NF_TARGET_HL) += ip6t_HL.o | |
| 31 | 29 | obj-$(CONFIG_IP6_NF_TARGET_LOG) += ip6t_LOG.o |
| 32 | 30 | obj-$(CONFIG_IP6_NF_TARGET_REJECT) += ip6t_REJECT.o |
| @@ -643,6 +643,7 @@ static void __exit ip6_queue_fini(void) · 642 unmodified lines | ||
| 643 | 643 | |
| 644 | 644 | MODULE_DESCRIPTION("IPv6 packet queue handler"); |
| 645 | 645 | MODULE_LICENSE("GPL"); |
| 646 | +MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_IP6_FW); | |
| 646 | 647 | |
| 647 | 648 | module_init(ip6_queue_init); |
| 648 | 649 | module_exit(ip6_queue_fini); |
| @@ -89,6 +89,25 @@ ip6t_ext_hdr(u8 nexthdr) · 88 unmodified lines | ||
| 89 | 89 | (nexthdr == IPPROTO_DSTOPTS) ); |
| 90 | 90 | } |
| 91 | 91 | |
| 92 | +static unsigned long ifname_compare(const char *_a, const char *_b, | |
| 93 | + const unsigned char *_mask) | |
| 94 | +{ | |
| 95 | + const unsigned long *a = (const unsigned long *)_a; | |
| 96 | + const unsigned long *b = (const unsigned long *)_b; | |
| 97 | + const unsigned long *mask = (const unsigned long *)_mask; | |
| 98 | + unsigned long ret; | |
| 99 | + | |
| 100 | + ret = (a[0] ^ b[0]) & mask[0]; | |
| 101 | + if (IFNAMSIZ > sizeof(unsigned long)) | |
| 102 | + ret |= (a[1] ^ b[1]) & mask[1]; | |
| 103 | + if (IFNAMSIZ > 2 * sizeof(unsigned long)) | |
| 104 | + ret |= (a[2] ^ b[2]) & mask[2]; | |
| 105 | + if (IFNAMSIZ > 3 * sizeof(unsigned long)) | |
| 106 | + ret |= (a[3] ^ b[3]) & mask[3]; | |
| 107 | + BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | |
| 108 | + return ret; | |
| 109 | +} | |
| 110 | + | |
| 92 | 111 | /* Returns whether matches rule or not. */ |
| 93 | 112 | /* Performance critical - called for every packet */ |
| 94 | 113 | static inline bool |
| @@ -99,7 +118,6 @@ ip6_packet_match(const struct sk_buff *skb, · 4 unmodified lines | ||
| 99 | 118 | unsigned int *protoff, |
| 100 | 119 | int *fragoff, bool *hotdrop) |
| 101 | 120 | { |
| 102 | − size_t i; | |
| 103 | 121 | unsigned long ret; |
| 104 | 122 | const struct ipv6hdr *ipv6 = ipv6_hdr(skb); |
| 105 | 123 | |
| @@ -120,12 +138,7 @@ ip6_packet_match(const struct sk_buff *skb, · 14 unmodified lines | ||
| 120 | 138 | return false; |
| 121 | 139 | } |
| 122 | 140 | |
| 123 | − /* Look for ifname matches; this should unroll nicely. */ | |
| 124 | − for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | |
| 125 | − ret |= (((const unsigned long *)indev)[i] | |
| 126 | − ^ ((const unsigned long *)ip6info->iniface)[i]) | |
| 127 | − & ((const unsigned long *)ip6info->iniface_mask)[i]; | |
| 128 | − } | |
| 141 | + ret = ifname_compare(indev, ip6info->iniface, ip6info->iniface_mask); | |
| 129 | 142 | |
| 130 | 143 | if (FWINV(ret != 0, IP6T_INV_VIA_IN)) { |
| 131 | 144 | dprintf("VIA in mismatch (%s vs %s).%s\n", |
| @@ -134,11 +147,7 @@ ip6_packet_match(const struct sk_buff *skb, · 2 unmodified lines | ||
| 134 | 147 | return false; |
| 135 | 148 | } |
| 136 | 149 | |
| 137 | − for (i = 0, ret = 0; i < IFNAMSIZ/sizeof(unsigned long); i++) { | |
| 138 | − ret |= (((const unsigned long *)outdev)[i] | |
| 139 | − ^ ((const unsigned long *)ip6info->outiface)[i]) | |
| 140 | − & ((const unsigned long *)ip6info->outiface_mask)[i]; | |
| 141 | − } | |
| 150 | + ret = ifname_compare(outdev, ip6info->outiface, ip6info->outiface_mask); | |
| 142 | 151 | |
| 143 | 152 | if (FWINV(ret != 0, IP6T_INV_VIA_OUT)) { |
| 144 | 153 | dprintf("VIA out mismatch (%s vs %s).%s\n", |
| @@ -373,10 +382,12 @@ ip6t_do_table(struct sk_buff *skb, · 228 unmodified lines | ||
| 373 | 382 | mtpar.family = tgpar.family = NFPROTO_IPV6; |
| 374 | 383 | tgpar.hooknum = hook; |
| 375 | 384 | |
| 376 | − read_lock_bh(&table->lock); | |
| 377 | 385 | IP_NF_ASSERT(table->valid_hooks & (1 << hook)); |
| 378 | − private = table->private; | |
| 379 | − table_base = (void *)private->entries[smp_processor_id()]; | |
| 386 | + | |
| 387 | + rcu_read_lock(); | |
| 388 | + private = rcu_dereference(table->private); | |
| 389 | + table_base = rcu_dereference(private->entries[smp_processor_id()]); | |
| 390 | + | |
| 380 | 391 | e = get_entry(table_base, private->hook_entry[hook]); |
| 381 | 392 | |
| 382 | 393 | /* For return from builtin chain */ |
| @@ -474,7 +485,7 @@ ip6t_do_table(struct sk_buff *skb, · 91 unmodified lines | ||
| 474 | 485 | #ifdef CONFIG_NETFILTER_DEBUG |
| 475 | 486 | ((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON; |
| 476 | 487 | #endif |
| 477 | − read_unlock_bh(&table->lock); | |
| 488 | + rcu_read_unlock(); | |
| 478 | 489 | |
| 479 | 490 | #ifdef DEBUG_ALLOW_ALL |
| 480 | 491 | return NF_ACCEPT; |
| @@ -955,11 +966,64 @@ get_counters(const struct xt_table_info *t, · 474 unmodified lines | ||
| 955 | 966 | } |
| 956 | 967 | } |
| 957 | 968 | |
| 969 | +/* We're lazy, and add to the first CPU; overflow works its fey magic | |
| 970 | + * and everything is OK. */ | |
| 971 | +static int | |
| 972 | +add_counter_to_entry(struct ip6t_entry *e, | |
| 973 | + const struct xt_counters addme[], | |
| 974 | + unsigned int *i) | |
| 975 | +{ | |
| 976 | + ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | |
| 977 | + | |
| 978 | + (*i)++; | |
| 979 | + return 0; | |
| 980 | +} | |
| 981 | + | |
| 982 | +/* Take values from counters and add them back onto the current cpu */ | |
| 983 | +static void put_counters(struct xt_table_info *t, | |
| 984 | + const struct xt_counters counters[]) | |
| 985 | +{ | |
| 986 | + unsigned int i, cpu; | |
| 987 | + | |
| 988 | + local_bh_disable(); | |
| 989 | + cpu = smp_processor_id(); | |
| 990 | + i = 0; | |
| 991 | + IP6T_ENTRY_ITERATE(t->entries[cpu], | |
| 992 | + t->size, | |
| 993 | + add_counter_to_entry, | |
| 994 | + counters, | |
| 995 | + &i); | |
| 996 | + local_bh_enable(); | |
| 997 | +} | |
| 998 | + | |
| 999 | +static inline int | |
| 1000 | +zero_entry_counter(struct ip6t_entry *e, void *arg) | |
| 1001 | +{ | |
| 1002 | + e->counters.bcnt = 0; | |
| 1003 | + e->counters.pcnt = 0; | |
| 1004 | + return 0; | |
| 1005 | +} | |
| 1006 | + | |
| 1007 | +static void | |
| 1008 | +clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info) | |
| 1009 | +{ | |
| 1010 | + unsigned int cpu; | |
| 1011 | + const void *loc_cpu_entry = info->entries[raw_smp_processor_id()]; | |
| 1012 | + | |
| 1013 | + memcpy(newinfo, info, offsetof(struct xt_table_info, entries)); | |
| 1014 | + for_each_possible_cpu(cpu) { | |
| 1015 | + memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size); | |
| 1016 | + IP6T_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size, | |
| 1017 | + zero_entry_counter, NULL); | |
| 1018 | + } | |
| 1019 | +} | |
| 1020 | + | |
| 958 | 1021 | static struct xt_counters *alloc_counters(struct xt_table *table) |
| 959 | 1022 | { |
| 960 | 1023 | unsigned int countersize; |
| 961 | 1024 | struct xt_counters *counters; |
| 962 | − const struct xt_table_info *private = table->private; | |
| 1025 | + struct xt_table_info *private = table->private; | |
| 1026 | + struct xt_table_info *info; | |
| 963 | 1027 | |
| 964 | 1028 | /* We need atomic snapshot of counters: rest doesn't change |
| 965 | 1029 | (other than comefrom, which userspace doesn't care |
| @@ -968,14 +1032,28 @@ static struct xt_counters *alloc_counters(struct xt_table *table) · 2 unmodified lines | ||
| 968 | 1032 | counters = vmalloc_node(countersize, numa_node_id()); |
| 969 | 1033 | |
| 970 | 1034 | if (counters == NULL) |
| 971 | − return ERR_PTR(-ENOMEM); | |
| 1035 | + goto nomem; | |
| 1036 | + | |
| 1037 | + info = xt_alloc_table_info(private->size); | |
| 1038 | + if (!info) | |
| 1039 | + goto free_counters; | |
| 1040 | + | |
| 1041 | + clone_counters(info, private); | |
| 972 | 1042 | |
| 973 | − /* First, sum counters... */ | |
| 974 | − write_lock_bh(&table->lock); | |
| 975 | − get_counters(private, counters); | |
| 976 | − write_unlock_bh(&table->lock); | |
| 1043 | + mutex_lock(&table->lock); | |
| 1044 | + xt_table_entry_swap_rcu(private, info); | |
| 1045 | + synchronize_net(); /* Wait until smoke has cleared */ | |
| 977 | 1046 | |
| 978 | − return counters; | |
| 1047 | + get_counters(info, counters); | |
| 1048 | + put_counters(private, counters); | |
| 1049 | + mutex_unlock(&table->lock); | |
| 1050 | + | |
| 1051 | + xt_free_table_info(info); | |
| 1052 | + | |
| 1053 | + free_counters: | |
| 1054 | + vfree(counters); | |
| 1055 | + nomem: | |
| 1056 | + return ERR_PTR(-ENOMEM); | |
| 979 | 1057 | } |
| 980 | 1058 | |
| 981 | 1059 | static int |
| @@ -1342,28 +1420,6 @@ do_replace(struct net *net, void __user *user, unsigned int len) · 360 unmodified lines | ||
| 1342 | 1420 | return ret; |
| 1343 | 1421 | } |
| 1344 | 1422 | |
| 1345 | −/* We're lazy, and add to the first CPU; overflow works its fey magic | |
| 1346 | − * and everything is OK. */ | |
| 1347 | −static inline int | |
| 1348 | −add_counter_to_entry(struct ip6t_entry *e, | |
| 1349 | − const struct xt_counters addme[], | |
| 1350 | − unsigned int *i) | |
| 1351 | −{ | |
| 1352 | −#if 0 | |
| 1353 | − duprintf("add_counter: Entry %u %lu/%lu + %lu/%lu\n", | |
| 1354 | − *i, | |
| 1355 | − (long unsigned int)e->counters.pcnt, | |
| 1356 | − (long unsigned int)e->counters.bcnt, | |
| 1357 | − (long unsigned int)addme[*i].pcnt, | |
| 1358 | − (long unsigned int)addme[*i].bcnt); | |
| 1359 | −#endif | |
| 1360 | − | |
| 1361 | − ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt); | |
| 1362 | − | |
| 1363 | − (*i)++; | |
| 1364 | − return 0; | |
| 1365 | −} | |
| 1366 | − | |
| 1367 | 1423 | static int |
| 1368 | 1424 | do_add_counters(struct net *net, void __user *user, unsigned int len, |
| 1369 | 1425 | int compat) |
| @@ -1424,13 +1480,14 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, · 54 unmodified lines | ||
| 1424 | 1480 | goto free; |
| 1425 | 1481 | } |
| 1426 | 1482 | |
| 1427 | − write_lock_bh(&t->lock); | |
| 1483 | + mutex_lock(&t->lock); | |
| 1428 | 1484 | private = t->private; |
| 1429 | 1485 | if (private->number != num_counters) { |
| 1430 | 1486 | ret = -EINVAL; |
| 1431 | 1487 | goto unlock_up_free; |
| 1432 | 1488 | } |
| 1433 | 1489 | |
| 1490 | + preempt_disable(); | |
| 1434 | 1491 | i = 0; |
| 1435 | 1492 | /* Choose the copy that is on our node */ |
| 1436 | 1493 | loc_cpu_entry = private->entries[raw_smp_processor_id()]; |
| @@ -1439,8 +1496,9 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, · 2 unmodified lines | ||
| 1439 | 1496 | add_counter_to_entry, |
| 1440 | 1497 | paddc, |
| 1441 | 1498 | &i); |
| 1499 | + preempt_enable(); | |
| 1442 | 1500 | unlock_up_free: |
| 1443 | − write_unlock_bh(&t->lock); | |
| 1501 | + mutex_unlock(&t->lock); | |
| 1444 | 1502 | xt_table_unlock(t); |
| 1445 | 1503 | module_put(t->me); |
| 1446 | 1504 | free: |
| @@ -1,95 +0,0 @@ | ||
| 1 | −/* | |
| 2 | − * Hop Limit modification target for ip6tables | |
| 3 | − * Maciej Soltysiak <solt@dns.toxicfilms.tv> | |
| 4 | − * Based on HW's TTL module | |
| 5 | − * | |
| 6 | − * This software is distributed under the terms of GNU GPL | |
| 7 | − */ | |
| 8 | − | |
| 9 | −#include <linux/module.h> | |
| 10 | −#include <linux/skbuff.h> | |
| 11 | −#include <linux/ip.h> | |
| 12 | −#include <linux/ipv6.h> | |
| 13 | − | |
| 14 | −#include <linux/netfilter/x_tables.h> | |
| 15 | −#include <linux/netfilter_ipv6/ip6t_HL.h> | |
| 16 | − | |
| 17 | −MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | |
| 18 | −MODULE_DESCRIPTION("Xtables: IPv6 Hop Limit field modification target"); | |
| 19 | −MODULE_LICENSE("GPL"); | |
| 20 | − | |
| 21 | −static unsigned int | |
| 22 | −hl_tg6(struct sk_buff *skb, const struct xt_target_param *par) | |
| 23 | −{ | |
| 24 | − struct ipv6hdr *ip6h; | |
| 25 | − const struct ip6t_HL_info *info = par->targinfo; | |
| 26 | − int new_hl; | |
| 27 | − | |
| 28 | − if (!skb_make_writable(skb, skb->len)) | |
| 29 | − return NF_DROP; | |
| 30 | − | |
| 31 | − ip6h = ipv6_hdr(skb); | |
| 32 | − | |
| 33 | − switch (info->mode) { | |
| 34 | − case IP6T_HL_SET: | |
| 35 | − new_hl = info->hop_limit; | |
| 36 | − break; | |
| 37 | − case IP6T_HL_INC: | |
| 38 | − new_hl = ip6h->hop_limit + info->hop_limit; | |
| 39 | − if (new_hl > 255) | |
| 40 | − new_hl = 255; | |
| 41 | − break; | |
| 42 | − case IP6T_HL_DEC: | |
| 43 | − new_hl = ip6h->hop_limit - info->hop_limit; | |
| 44 | − if (new_hl < 0) | |
| 45 | − new_hl = 0; | |
| 46 | − break; | |
| 47 | − default: | |
| 48 | − new_hl = ip6h->hop_limit; | |
| 49 | − break; | |
| 50 | − } | |
| 51 | − | |
| 52 | − ip6h->hop_limit = new_hl; | |
| 53 | − | |
| 54 | − return XT_CONTINUE; | |
| 55 | −} | |
| 56 | − | |
| 57 | −static bool hl_tg6_check(const struct xt_tgchk_param *par) | |
| 58 | −{ | |
| 59 | − const struct ip6t_HL_info *info = par->targinfo; | |
| 60 | − | |
| 61 | − if (info->mode > IP6T_HL_MAXMODE) { | |
| 62 | − printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", | |
| 63 | − info->mode); | |
| 64 | − return false; | |
| 65 | − } | |
| 66 | − if (info->mode != IP6T_HL_SET && info->hop_limit == 0) { | |
| 67 | − printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " | |
| 68 | − "make sense with value 0\n"); | |
| 69 | − return false; | |
| 70 | − } | |
| 71 | − return true; | |
| 72 | −} | |
| 73 | − | |
| 74 | −static struct xt_target hl_tg6_reg __read_mostly = { | |
| 75 | − .name = "HL", | |
| 76 | − .family = NFPROTO_IPV6, | |
| 77 | − .target = hl_tg6, | |
| 78 | − .targetsize = sizeof(struct ip6t_HL_info), | |
| 79 | − .table = "mangle", | |
| 80 | − .checkentry = hl_tg6_check, | |
| 81 | − .me = THIS_MODULE | |
| 82 | −}; | |
| 83 | − | |
| 84 | −static int __init hl_tg6_init(void) | |
| 85 | −{ | |
| 86 | − return xt_register_target(&hl_tg6_reg); | |
| 87 | −} | |
| 88 | − | |
| 89 | −static void __exit hl_tg6_exit(void) | |
| 90 | −{ | |
| 91 | − xt_unregister_target(&hl_tg6_reg); | |
| 92 | −} | |
| 93 | − | |
| 94 | −module_init(hl_tg6_init); | |
| 95 | −module_exit(hl_tg6_exit); | |
| @@ -477,7 +477,7 @@ static struct xt_target log_tg6_reg __read_mostly = { · 476 unmodified lines | ||
| 477 | 477 | .me = THIS_MODULE, |
| 478 | 478 | }; |
| 479 | 479 | |
| 480 | −static const struct nf_logger ip6t_logger = { | |
| 480 | +static struct nf_logger ip6t_logger __read_mostly = { | |
| 481 | 481 | .name = "ip6t_LOG", |
| 482 | 482 | .logfn = &ip6t_log_packet, |
| 483 | 483 | .me = THIS_MODULE, |
| @@ -1,68 +0,0 @@ | ||
| 1 | −/* Hop Limit matching module */ | |
| 2 | − | |
| 3 | −/* (C) 2001-2002 Maciej Soltysiak <solt@dns.toxicfilms.tv> | |
| 4 | − * Based on HW's ttl module | |
| 5 | − * | |
| 6 | − * This program is free software; you can redistribute it and/or modify | |
| 7 | − * it under the terms of the GNU General Public License version 2 as | |
| 8 | − * published by the Free Software Foundation. | |
| 9 | − */ | |
| 10 | − | |
| 11 | −#include <linux/ipv6.h> | |
| 12 | −#include <linux/module.h> | |
| 13 | −#include <linux/skbuff.h> | |
| 14 | − | |
| 15 | −#include <linux/netfilter_ipv6/ip6t_hl.h> | |
| 16 | −#include <linux/netfilter/x_tables.h> | |
| 17 | − | |
| 18 | −MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | |
| 19 | −MODULE_DESCRIPTION("Xtables: IPv6 Hop Limit field match"); | |
| 20 | −MODULE_LICENSE("GPL"); | |
| 21 | − | |
| 22 | −static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |
| 23 | −{ | |
| 24 | − const struct ip6t_hl_info *info = par->matchinfo; | |
| 25 | − const struct ipv6hdr *ip6h = ipv6_hdr(skb); | |
| 26 | − | |
| 27 | − switch (info->mode) { | |
| 28 | − case IP6T_HL_EQ: | |
| 29 | − return ip6h->hop_limit == info->hop_limit; | |
| 30 | − break; | |
| 31 | − case IP6T_HL_NE: | |
| 32 | − return ip6h->hop_limit != info->hop_limit; | |
| 33 | − break; | |
| 34 | − case IP6T_HL_LT: | |
| 35 | − return ip6h->hop_limit < info->hop_limit; | |
| 36 | − break; | |
| 37 | − case IP6T_HL_GT: | |
| 38 | − return ip6h->hop_limit > info->hop_limit; | |
| 39 | − break; | |
| 40 | − default: | |
| 41 | − printk(KERN_WARNING "ip6t_hl: unknown mode %d\n", | |
| 42 | − info->mode); | |
| 43 | − return false; | |
| 44 | − } | |
| 45 | − | |
| 46 | − return false; | |
| 47 | −} | |
| 48 | − | |
| 49 | −static struct xt_match hl_mt6_reg __read_mostly = { | |
| 50 | − .name = "hl", | |
| 51 | − .family = NFPROTO_IPV6, | |
| 52 | − .match = hl_mt6, | |
| 53 | − .matchsize = sizeof(struct ip6t_hl_info), | |
| 54 | − .me = THIS_MODULE, | |
| 55 | −}; | |
| 56 | − | |
| 57 | −static int __init hl_mt6_init(void) | |
| 58 | −{ | |
| 59 | − return xt_register_match(&hl_mt6_reg); | |
| 60 | −} | |
| 61 | − | |
| 62 | −static void __exit hl_mt6_exit(void) | |
| 63 | −{ | |
| 64 | − xt_unregister_match(&hl_mt6_reg); | |
| 65 | −} | |
| 66 | − | |
| 67 | −module_init(hl_mt6_init); | |
| 68 | −module_exit(hl_mt6_exit); | |
| @@ -54,7 +54,6 @@ static struct · 53 unmodified lines | ||
| 54 | 54 | static struct xt_table packet_filter = { |
| 55 | 55 | .name = "filter", |
| 56 | 56 | .valid_hooks = FILTER_VALID_HOOKS, |
| 57 | − .lock = __RW_LOCK_UNLOCKED(packet_filter.lock), | |
| 58 | 57 | .me = THIS_MODULE, |
| 59 | 58 | .af = AF_INET6, |
| 60 | 59 | }; |
| @@ -60,7 +60,6 @@ static struct · 59 unmodified lines | ||
| 60 | 60 | static struct xt_table packet_mangler = { |
| 61 | 61 | .name = "mangle", |
| 62 | 62 | .valid_hooks = MANGLE_VALID_HOOKS, |
| 63 | − .lock = __RW_LOCK_UNLOCKED(packet_mangler.lock), | |
| 64 | 63 | .me = THIS_MODULE, |
| 65 | 64 | .af = AF_INET6, |
| 66 | 65 | }; |
| @@ -38,7 +38,6 @@ static struct · 37 unmodified lines | ||
| 38 | 38 | static struct xt_table packet_raw = { |
| 39 | 39 | .name = "raw", |
| 40 | 40 | .valid_hooks = RAW_VALID_HOOKS, |
| 41 | − .lock = __RW_LOCK_UNLOCKED(packet_raw.lock), | |
| 42 | 41 | .me = THIS_MODULE, |
| 43 | 42 | .af = AF_INET6, |
| 44 | 43 | }; |
| @@ -59,7 +59,6 @@ static struct · 58 unmodified lines | ||
| 59 | 59 | static struct xt_table security_table = { |
| 60 | 60 | .name = "security", |
| 61 | 61 | .valid_hooks = SECURITY_VALID_HOOKS, |
| 62 | − .lock = __RW_LOCK_UNLOCKED(security_table.lock), | |
| 63 | 62 | .me = THIS_MODULE, |
| 64 | 63 | .af = AF_INET6, |
| 65 | 64 | }; |
| @@ -26,6 +26,7 @@ · 25 unmodified lines | ||
| 26 | 26 | #include <net/netfilter/nf_conntrack_l4proto.h> |
| 27 | 27 | #include <net/netfilter/nf_conntrack_l3proto.h> |
| 28 | 28 | #include <net/netfilter/nf_conntrack_core.h> |
| 29 | +#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | |
| 29 | 30 | |
| 30 | 31 | static bool ipv6_pkt_to_tuple(const struct sk_buff *skb, unsigned int nhoff, |
| 31 | 32 | struct nf_conntrack_tuple *tuple) |
| @@ -126,6 +126,10 @@ static bool icmpv6_new(struct nf_conn *ct, const struct sk_buff *skb, · 125 unmodified lines | ||
| 126 | 126 | pr_debug("icmpv6: can't create new conn with type %u\n", |
| 127 | 127 | type + 128); |
| 128 | 128 | nf_ct_dump_tuple_ipv6(&ct->tuplehash[0].tuple); |
| 129 | + if (LOG_INVALID(nf_ct_net(ct), IPPROTO_ICMPV6)) | |
| 130 | + nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL, | |
| 131 | + "nf_ct_icmpv6: invalid new with type %d ", | |
| 132 | + type + 128); | |
| 129 | 133 | return false; |
| 130 | 134 | } |
| 131 | 135 | atomic_set(&ct->proto.icmp.count, 0); |
| @@ -357,6 +357,45 @@ config NETFILTER_XT_TARGET_DSCP · 356 unmodified lines | ||
| 357 | 357 | |
| 358 | 358 | To compile it as a module, choose M here. If unsure, say N. |
| 359 | 359 | |
| 360 | +config NETFILTER_XT_TARGET_HL | |
| 361 | + tristate '"HL" hoplimit target support' | |
| 362 | + depends on IP_NF_MANGLE || IP6_NF_MANGLE | |
| 363 | + depends on NETFILTER_ADVANCED | |
| 364 | + ---help--- | |
| 365 | + This option adds the "HL" (for IPv6) and "TTL" (for IPv4) | |
| 366 | + targets, which enable the user to change the | |
| 367 | + hoplimit/time-to-live value of the IP header. | |
| 368 | + | |
| 369 | + While it is safe to decrement the hoplimit/TTL value, the | |
| 370 | + modules also allow to increment and set the hoplimit value of | |
| 371 | + the header to arbitrary values. This is EXTREMELY DANGEROUS | |
| 372 | + since you can easily create immortal packets that loop | |
| 373 | + forever on the network. | |
| 374 | + | |
| 375 | +config NETFILTER_XT_TARGET_LED | |
| 376 | + tristate '"LED" target support' | |
| 377 | + depends on LEDS_CLASS | |
| 378 | + depends on NETFILTER_ADVANCED | |
| 379 | + help | |
| 380 | + This option adds a `LED' target, which allows you to blink LEDs in | |
| 381 | + response to particular packets passing through your machine. | |
| 382 | + | |
| 383 | + This can be used to turn a spare LED into a network activity LED, | |
| 384 | + which only flashes in response to FTP transfers, for example. Or | |
| 385 | + you could have an LED which lights up for a minute or two every time | |
| 386 | + somebody connects to your machine via SSH. | |
| 387 | + | |
| 388 | + You will need support for the "led" class to make this work. | |
| 389 | + | |
| 390 | + To create an LED trigger for incoming SSH traffic: | |
| 391 | + iptables -A INPUT -p tcp --dport 22 -j LED --led-trigger-id ssh --led-delay 1000 | |
| 392 | + | |
| 393 | + Then attach the new trigger to an LED on your system: | |
| 394 | + echo netfilter-ssh > /sys/class/leds/<ledname>/trigger | |
| 395 | + | |
| 396 | + For more information on the LEDs available on your system, see | |
| 397 | + Documentation/leds-class.txt | |
| 398 | + | |
| 360 | 399 | config NETFILTER_XT_TARGET_MARK |
| 361 | 400 | tristate '"MARK" target support' |
| 362 | 401 | default m if NETFILTER_ADVANCED=n |
| @@ -488,6 +527,22 @@ config NETFILTER_XT_TARGET_TCPOPTSTRIP · 125 unmodified lines | ||
| 488 | 527 | This option adds a "TCPOPTSTRIP" target, which allows you to strip |
| 489 | 528 | TCP options from TCP packets. |
| 490 | 529 | |
| 530 | +config NETFILTER_XT_MATCH_CLUSTER | |
| 531 | + tristate '"cluster" match support' | |
| 532 | + depends on NF_CONNTRACK | |
| 533 | + depends on NETFILTER_ADVANCED | |
| 534 | + ---help--- | |
| 535 | + This option allows you to build work-load-sharing clusters of | |
| 536 | + network servers/stateful firewalls without having a dedicated | |
| 537 | + load-balancing router/server/switch. Basically, this match returns | |
| 538 | + true when the packet must be handled by this cluster node. Thus, | |
| 539 | + all nodes see all packets and this match decides which node handles | |
| 540 | + what packets. The work-load sharing algorithm is based on source | |
| 541 | + address hashing. | |
| 542 | + | |
| 543 | + If you say Y or M here, try `iptables -m cluster --help` for | |
| 544 | + more information. | |
| 545 | + | |
| 491 | 546 | config NETFILTER_XT_MATCH_COMMENT |
| 492 | 547 | tristate '"comment" match support' |
| 493 | 548 | depends on NETFILTER_ADVANCED |
| @@ -605,6 +660,14 @@ config NETFILTER_XT_MATCH_HELPER · 111 unmodified lines | ||
| 605 | 660 | |
| 606 | 661 | To compile it as a module, choose M here. If unsure, say Y. |
| 607 | 662 | |
| 663 | +config NETFILTER_XT_MATCH_HL | |
| 664 | + tristate '"hl" hoplimit/TTL match support' | |
| 665 | + depends on NETFILTER_ADVANCED | |
| 666 | + ---help--- | |
| 667 | + HL matching allows you to match packets based on the hoplimit | |
| 668 | + in the IPv6 header, or the time-to-live field in the IPv4 | |
| 669 | + header of the packet. | |
| 670 | + | |
| 608 | 671 | config NETFILTER_XT_MATCH_IPRANGE |
| 609 | 672 | tristate '"iprange" address range match support' |
| 610 | 673 | depends on NETFILTER_ADVANCED |
| @@ -45,6 +45,8 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o · 44 unmodified lines | ||
| 45 | 45 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o |
| 46 | 46 | obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o |
| 47 | 47 | obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o |
| 48 | +obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o | |
| 49 | +obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o | |
| 48 | 50 | obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o |
| 49 | 51 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o |
| 50 | 52 | obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o |
| @@ -57,6 +59,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o · 6 unmodified lines | ||
| 57 | 59 | obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o |
| 58 | 60 | |
| 59 | 61 | # matches |
| 62 | +obj-$(CONFIG_NETFILTER_XT_MATCH_CLUSTER) += xt_cluster.o | |
| 60 | 63 | obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o |
| 61 | 64 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNBYTES) += xt_connbytes.o |
| 62 | 65 | obj-$(CONFIG_NETFILTER_XT_MATCH_CONNLIMIT) += xt_connlimit.o |
| @@ -67,6 +70,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_DSCP) += xt_dscp.o · 4 unmodified lines | ||
| 67 | 70 | obj-$(CONFIG_NETFILTER_XT_MATCH_ESP) += xt_esp.o |
| 68 | 71 | obj-$(CONFIG_NETFILTER_XT_MATCH_HASHLIMIT) += xt_hashlimit.o |
| 69 | 72 | obj-$(CONFIG_NETFILTER_XT_MATCH_HELPER) += xt_helper.o |
| 73 | +obj-$(CONFIG_NETFILTER_XT_MATCH_HL) += xt_hl.o | |
| 70 | 74 | obj-$(CONFIG_NETFILTER_XT_MATCH_IPRANGE) += xt_iprange.o |
| 71 | 75 | obj-$(CONFIG_NETFILTER_XT_MATCH_LENGTH) += xt_length.o |
| 72 | 76 | obj-$(CONFIG_NETFILTER_XT_MATCH_LIMIT) += xt_limit.o |
| @@ -174,7 +174,6 @@ next_hook: · 173 unmodified lines | ||
| 174 | 174 | outdev, &elem, okfn, hook_thresh); |
| 175 | 175 | if (verdict == NF_ACCEPT || verdict == NF_STOP) { |
| 176 | 176 | ret = 1; |
| 177 | − goto unlock; | |
| 178 | 177 | } else if (verdict == NF_DROP) { |
| 179 | 178 | kfree_skb(skb); |
| 180 | 179 | ret = -EPERM; |
| @@ -183,7 +182,6 @@ next_hook: · 2 unmodified lines | ||
| 183 | 182 | verdict >> NF_VERDICT_BITS)) |
| 184 | 183 | goto next_hook; |
| 185 | 184 | } |
| 186 | −unlock: | |
| 187 | 185 | rcu_read_unlock(); |
| 188 | 186 | return ret; |
| 189 | 187 | } |
| @@ -54,7 +54,7 @@ EXPORT_SYMBOL_GPL(nf_conntrack_lock); · 53 unmodified lines | ||
| 54 | 54 | unsigned int nf_conntrack_htable_size __read_mostly; |
| 55 | 55 | EXPORT_SYMBOL_GPL(nf_conntrack_htable_size); |
| 56 | 56 | |
| 57 | −int nf_conntrack_max __read_mostly; | |
| 57 | +unsigned int nf_conntrack_max __read_mostly; | |
| 58 | 58 | EXPORT_SYMBOL_GPL(nf_conntrack_max); |
| 59 | 59 | |
| 60 | 60 | struct nf_conn nf_conntrack_untracked __read_mostly; |
| @@ -472,7 +472,8 @@ struct nf_conn *nf_conntrack_alloc(struct net *net, · 411 unmodified lines | ||
| 472 | 472 | struct nf_conn *ct; |
| 473 | 473 | |
| 474 | 474 | if (unlikely(!nf_conntrack_hash_rnd_initted)) { |
| 475 | − get_random_bytes(&nf_conntrack_hash_rnd, 4); | |
| 475 | + get_random_bytes(&nf_conntrack_hash_rnd, | |
| 476 | + sizeof(nf_conntrack_hash_rnd)); | |
| 476 | 477 | nf_conntrack_hash_rnd_initted = 1; |
| 477 | 478 | } |
| 478 | 479 | |
| @@ -516,16 +517,17 @@ EXPORT_SYMBOL_GPL(nf_conntrack_alloc); · 37 unmodified lines | ||
| 516 | 517 | static void nf_conntrack_free_rcu(struct rcu_head *head) |
| 517 | 518 | { |
| 518 | 519 | struct nf_conn *ct = container_of(head, struct nf_conn, rcu); |
| 519 | − struct net *net = nf_ct_net(ct); | |
| 520 | 520 | |
| 521 | 521 | nf_ct_ext_free(ct); |
| 522 | 522 | kmem_cache_free(nf_conntrack_cachep, ct); |
| 523 | − atomic_dec(&net->ct.count); | |
| 524 | 523 | } |
| 525 | 524 | |
| 526 | 525 | void nf_conntrack_free(struct nf_conn *ct) |
| 527 | 526 | { |
| 527 | + struct net *net = nf_ct_net(ct); | |
| 528 | + | |
| 528 | 529 | nf_ct_ext_destroy(ct); |
| 530 | + atomic_dec(&net->ct.count); | |
| 529 | 531 | call_rcu(&ct->rcu, nf_conntrack_free_rcu); |
| 530 | 532 | } |
| 531 | 533 | EXPORT_SYMBOL_GPL(nf_conntrack_free); |
| @@ -733,6 +735,8 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum, · 201 unmodified lines | ||
| 733 | 735 | nf_conntrack_put(skb->nfct); |
| 734 | 736 | skb->nfct = NULL; |
| 735 | 737 | NF_CT_STAT_INC_ATOMIC(net, invalid); |
| 738 | + if (ret == -NF_DROP) | |
| 739 | + NF_CT_STAT_INC_ATOMIC(net, drop); | |
| 736 | 740 | return -ret; |
| 737 | 741 | } |
| 738 | 742 | |
| @@ -1103,7 +1107,7 @@ int nf_conntrack_set_hashsize(const char *val, struct kernel_param *kp) · 364 unmodified lines | ||
| 1103 | 1107 | |
| 1104 | 1108 | /* We have to rehahs for the new table anyway, so we also can |
| 1105 | 1109 | * use a newrandom seed */ |
| 1106 | − get_random_bytes(&rnd, 4); | |
| 1110 | + get_random_bytes(&rnd, sizeof(rnd)); | |
| 1107 | 1111 | |
| 1108 | 1112 | /* Lookups in the old hash might happen in parallel, which means we |
| 1109 | 1113 | * might get false negatives during connection lookup. New connections |
| @@ -72,7 +72,8 @@ static unsigned int nf_ct_expect_dst_hash(const struct nf_conntrack_tuple *tuple · 71 unmodified lines | ||
| 72 | 72 | unsigned int hash; |
| 73 | 73 | |
| 74 | 74 | if (unlikely(!nf_ct_expect_hash_rnd_initted)) { |
| 75 | − get_random_bytes(&nf_ct_expect_hash_rnd, 4); | |
| 75 | + get_random_bytes(&nf_ct_expect_hash_rnd, | |
| 76 | + sizeof(nf_ct_expect_hash_rnd)); | |
| 76 | 77 | nf_ct_expect_hash_rnd_initted = 1; |
| 77 | 78 | } |
| 78 | 79 | |
| @@ -518,6 +518,7 @@ static int ctnetlink_conntrack_event(struct notifier_block *this, · 517 unmodified lines | ||
| 518 | 518 | nla_put_failure: |
| 519 | 519 | rcu_read_unlock(); |
| 520 | 520 | nlmsg_failure: |
| 521 | + nfnetlink_set_err(0, group, -ENOBUFS); | |
| 521 | 522 | kfree_skb(skb); |
| 522 | 523 | return NOTIFY_DONE; |
| 523 | 524 | } |
| @@ -599,7 +600,8 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple) · 75 unmodified lines | ||
| 599 | 600 | |
| 600 | 601 | nla_parse_nested(tb, CTA_IP_MAX, attr, NULL); |
| 601 | 602 | |
| 602 | − l3proto = nf_ct_l3proto_find_get(tuple->src.l3num); | |
| 603 | + rcu_read_lock(); | |
| 604 | + l3proto = __nf_ct_l3proto_find(tuple->src.l3num); | |
| 603 | 605 | |
| 604 | 606 | if (likely(l3proto->nlattr_to_tuple)) { |
| 605 | 607 | ret = nla_validate_nested(attr, CTA_IP_MAX, |
| @@ -608,7 +610,7 @@ ctnetlink_parse_tuple_ip(struct nlattr *attr, struct nf_conntrack_tuple *tuple) · 2 unmodified lines | ||
| 608 | 610 | ret = l3proto->nlattr_to_tuple(tb, tuple); |
| 609 | 611 | } |
| 610 | 612 | |
| 611 | − nf_ct_l3proto_put(l3proto); | |
| 613 | + rcu_read_unlock(); | |
| 612 | 614 | |
| 613 | 615 | return ret; |
| 614 | 616 | } |
| @@ -633,7 +635,8 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, · 18 unmodified lines | ||
| 633 | 635 | return -EINVAL; |
| 634 | 636 | tuple->dst.protonum = nla_get_u8(tb[CTA_PROTO_NUM]); |
| 635 | 637 | |
| 636 | − l4proto = nf_ct_l4proto_find_get(tuple->src.l3num, tuple->dst.protonum); | |
| 638 | + rcu_read_lock(); | |
| 639 | + l4proto = __nf_ct_l4proto_find(tuple->src.l3num, tuple->dst.protonum); | |
| 637 | 640 | |
| 638 | 641 | if (likely(l4proto->nlattr_to_tuple)) { |
| 639 | 642 | ret = nla_validate_nested(attr, CTA_PROTO_MAX, |
| @@ -642,7 +645,7 @@ ctnetlink_parse_tuple_proto(struct nlattr *attr, · 2 unmodified lines | ||
| 642 | 645 | ret = l4proto->nlattr_to_tuple(tb, tuple); |
| 643 | 646 | } |
| 644 | 647 | |
| 645 | − nf_ct_l4proto_put(l4proto); | |
| 648 | + rcu_read_unlock(); | |
| 646 | 649 | |
| 647 | 650 | return ret; |
| 648 | 651 | } |
| @@ -989,10 +992,11 @@ ctnetlink_change_protoinfo(struct nf_conn *ct, struct nlattr *cda[]) · 340 unmodified lines | ||
| 989 | 992 | |
| 990 | 993 | nla_parse_nested(tb, CTA_PROTOINFO_MAX, attr, NULL); |
| 991 | 994 | |
| 992 | − l4proto = nf_ct_l4proto_find_get(nf_ct_l3num(ct), nf_ct_protonum(ct)); | |
| 995 | + rcu_read_lock(); | |
| 996 | + l4proto = __nf_ct_l4proto_find(nf_ct_l3num(ct), nf_ct_protonum(ct)); | |
| 993 | 997 | if (l4proto->from_nlattr) |
| 994 | 998 | err = l4proto->from_nlattr(tb, ct); |
| 995 | − nf_ct_l4proto_put(l4proto); | |
| 999 | + rcu_read_unlock(); | |
| 996 | 1000 | |
| 997 | 1001 | return err; |
| 998 | 1002 | } |
| @@ -1062,6 +1066,10 @@ ctnetlink_change_conntrack(struct nf_conn *ct, struct nlattr *cda[]) · 63 unmodified lines | ||
| 1062 | 1066 | { |
| 1063 | 1067 | int err; |
| 1064 | 1068 | |
| 1069 | + /* only allow NAT changes and master assignation for new conntracks */ | |
| 1070 | + if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST] || cda[CTA_TUPLE_MASTER]) | |
| 1071 | + return -EOPNOTSUPP; | |
| 1072 | + | |
| 1065 | 1073 | if (cda[CTA_HELP]) { |
| 1066 | 1074 | err = ctnetlink_change_helper(ct, cda); |
| 1067 | 1075 | if (err < 0) |
| @@ -1124,13 +1132,11 @@ ctnetlink_event_report(struct nf_conn *ct, u32 pid, int report) · 56 unmodified lines | ||
| 1124 | 1132 | report); |
| 1125 | 1133 | } |
| 1126 | 1134 | |
| 1127 | −static int | |
| 1135 | +static struct nf_conn * | |
| 1128 | 1136 | ctnetlink_create_conntrack(struct nlattr *cda[], |
| 1129 | 1137 | struct nf_conntrack_tuple *otuple, |
| 1130 | 1138 | struct nf_conntrack_tuple *rtuple, |
| 1131 | − struct nf_conn *master_ct, | |
| 1132 | − u32 pid, | |
| 1133 | − int report) | |
| 1139 | + u8 u3) | |
| 1134 | 1140 | { |
| 1135 | 1141 | struct nf_conn *ct; |
| 1136 | 1142 | int err = -EINVAL; |
| @@ -1138,10 +1144,10 @@ ctnetlink_create_conntrack(struct nlattr *cda[], · 1 unmodified line | ||
| 1138 | 1144 | |
| 1139 | 1145 | ct = nf_conntrack_alloc(&init_net, otuple, rtuple, GFP_ATOMIC); |
| 1140 | 1146 | if (IS_ERR(ct)) |
| 1141 | − return -ENOMEM; | |
| 1147 | + return ERR_PTR(-ENOMEM); | |
| 1142 | 1148 | |
| 1143 | 1149 | if (!cda[CTA_TIMEOUT]) |
| 1144 | − goto err; | |
| 1150 | + goto err1; | |
| 1145 | 1151 | ct->timeout.expires = ntohl(nla_get_be32(cda[CTA_TIMEOUT])); |
| 1146 | 1152 | |
| 1147 | 1153 | ct->timeout.expires = jiffies + ct->timeout.expires * HZ; |
| @@ -1152,10 +1158,8 @@ ctnetlink_create_conntrack(struct nlattr *cda[], · 4 unmodified lines | ||
| 1152 | 1158 | char *helpname; |
| 1153 | 1159 | |
| 1154 | 1160 | err = ctnetlink_parse_help(cda[CTA_HELP], &helpname); |
| 1155 | − if (err < 0) { | |
| 1156 | − rcu_read_unlock(); | |
| 1157 | − goto err; | |
| 1158 | − } | |
| 1161 | + if (err < 0) | |
| 1162 | + goto err2; | |
| 1159 | 1163 | |
| 1160 | 1164 | helper = __nf_conntrack_helper_find_byname(helpname); |
| 1161 | 1165 | if (helper == NULL) { |
| @@ -1163,28 +1167,26 @@ ctnetlink_create_conntrack(struct nlattr *cda[], · 1 unmodified line | ||
| 1163 | 1167 | #ifdef CONFIG_MODULES |
| 1164 | 1168 | if (request_module("nfct-helper-%s", helpname) < 0) { |
| 1165 | 1169 | err = -EOPNOTSUPP; |
| 1166 | − goto err; | |
| 1170 | + goto err1; | |
| 1167 | 1171 | } |
| 1168 | 1172 | |
| 1169 | 1173 | rcu_read_lock(); |
| 1170 | 1174 | helper = __nf_conntrack_helper_find_byname(helpname); |
| 1171 | 1175 | if (helper) { |
| 1172 | − rcu_read_unlock(); | |
| 1173 | 1176 | err = -EAGAIN; |
| 1174 | − goto err; | |
| 1177 | + goto err2; | |
| 1175 | 1178 | } |
| 1176 | 1179 | rcu_read_unlock(); |
| 1177 | 1180 | #endif |
| 1178 | 1181 | err = -EOPNOTSUPP; |
| 1179 | − goto err; | |
| 1182 | + goto err1; | |
| 1180 | 1183 | } else { |
| 1181 | 1184 | struct nf_conn_help *help; |
| 1182 | 1185 | |
| 1183 | 1186 | help = nf_ct_helper_ext_add(ct, GFP_ATOMIC); |
| 1184 | 1187 | if (help == NULL) { |
| 1185 | − rcu_read_unlock(); | |
| 1186 | 1188 | err = -ENOMEM; |
| 1187 | − goto err; | |
| 1189 | + goto err2; | |
| 1188 | 1190 | } |
| 1189 | 1191 | |
| 1190 | 1192 | /* not in hash table yet so not strictly necessary */ |
| @@ -1193,44 +1195,34 @@ ctnetlink_create_conntrack(struct nlattr *cda[], · 2 unmodified lines | ||
| 1193 | 1195 | } else { |
| 1194 | 1196 | /* try an implicit helper assignation */ |
| 1195 | 1197 | err = __nf_ct_try_assign_helper(ct, GFP_ATOMIC); |
| 1196 | − if (err < 0) { | |
| 1197 | − rcu_read_unlock(); | |
| 1198 | − goto err; | |
| 1199 | − } | |
| 1198 | + if (err < 0) | |
| 1199 | + goto err2; | |
| 1200 | 1200 | } |
| 1201 | 1201 | |
| 1202 | 1202 | if (cda[CTA_STATUS]) { |
| 1203 | 1203 | err = ctnetlink_change_status(ct, cda); |
| 1204 | − if (err < 0) { | |
| 1205 | − rcu_read_unlock(); | |
| 1206 | − goto err; | |
| 1207 | − } | |
| 1204 | + if (err < 0) | |
| 1205 | + goto err2; | |
| 1208 | 1206 | } |
| 1209 | 1207 | |
| 1210 | 1208 | if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { |
| 1211 | 1209 | err = ctnetlink_change_nat(ct, cda); |
| 1212 | − if (err < 0) { | |
| 1213 | − rcu_read_unlock(); | |
| 1214 | − goto err; | |
| 1215 | − } | |
| 1210 | + if (err < 0) | |
| 1211 | + goto err2; | |
| 1216 | 1212 | } |
| 1217 | 1213 | |
| 1218 | 1214 | #ifdef CONFIG_NF_NAT_NEEDED |
| 1219 | 1215 | if (cda[CTA_NAT_SEQ_ADJ_ORIG] || cda[CTA_NAT_SEQ_ADJ_REPLY]) { |
| 1220 | 1216 | err = ctnetlink_change_nat_seq_adj(ct, cda); |
| 1221 | − if (err < 0) { | |
| 1222 | − rcu_read_unlock(); | |
| 1223 | − goto err; | |
| 1224 | − } | |
| 1217 | + if (err < 0) | |
| 1218 | + goto err2; | |
| 1225 | 1219 | } |
| 1226 | 1220 | #endif |
| 1227 | 1221 | |
| 1228 | 1222 | if (cda[CTA_PROTOINFO]) { |
| 1229 | 1223 | err = ctnetlink_change_protoinfo(ct, cda); |
| 1230 | − if (err < 0) { | |
| 1231 | − rcu_read_unlock(); | |
| 1232 | − goto err; | |
| 1233 | − } | |
| 1224 | + if (err < 0) | |
| 1225 | + goto err2; | |
| 1234 | 1226 | } |
| 1235 | 1227 | |
| 1236 | 1228 | nf_ct_acct_ext_add(ct, GFP_ATOMIC); |
| @@ -1241,23 +1233,37 @@ ctnetlink_create_conntrack(struct nlattr *cda[], · 4 unmodified lines | ||
| 1241 | 1233 | #endif |
| 1242 | 1234 | |
| 1243 | 1235 | /* setup master conntrack: this is a confirmed expectation */ |
| 1244 | − if (master_ct) { | |
| 1236 | + if (cda[CTA_TUPLE_MASTER]) { | |
| 1237 | + struct nf_conntrack_tuple master; | |
| 1238 | + struct nf_conntrack_tuple_hash *master_h; | |
| 1239 | + struct nf_conn *master_ct; | |
| 1240 | + | |
| 1241 | + err = ctnetlink_parse_tuple(cda, &master, CTA_TUPLE_MASTER, u3); | |
| 1242 | + if (err < 0) | |
| 1243 | + goto err2; | |
| 1244 | + | |
| 1245 | + master_h = __nf_conntrack_find(&init_net, &master); | |
| 1246 | + if (master_h == NULL) { | |
| 1247 | + err = -ENOENT; | |
| 1248 | + goto err2; | |
| 1249 | + } | |
| 1250 | + master_ct = nf_ct_tuplehash_to_ctrack(master_h); | |
| 1251 | + nf_conntrack_get(&master_ct->ct_general); | |
| 1245 | 1252 | __set_bit(IPS_EXPECTED_BIT, &ct->status); |
| 1246 | 1253 | ct->master = master_ct; |
| 1247 | 1254 | } |
| 1248 | 1255 | |
| 1249 | − nf_conntrack_get(&ct->ct_general); | |
| 1250 | 1256 | add_timer(&ct->timeout); |
| 1251 | 1257 | nf_conntrack_hash_insert(ct); |
| 1252 | 1258 | rcu_read_unlock(); |
| 1253 | − ctnetlink_event_report(ct, pid, report); | |
| 1254 | − nf_ct_put(ct); | |
| 1255 | 1259 | |
| 1256 | − return 0; | |
| 1260 | + return ct; | |
| 1257 | 1261 | |
| 1258 | −err: | |
| 1262 | +err2: | |
| 1263 | + rcu_read_unlock(); | |
| 1264 | +err1: | |
| 1259 | 1265 | nf_conntrack_free(ct); |
| 1260 | − return err; | |
| 1266 | + return ERR_PTR(err); | |
| 1261 | 1267 | } |
| 1262 | 1268 | |
| 1263 | 1269 | static int |
| @@ -1289,38 +1295,25 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, · 25 unmodified lines | ||
| 1289 | 1295 | h = __nf_conntrack_find(&init_net, &rtuple); |
| 1290 | 1296 | |
| 1291 | 1297 | if (h == NULL) { |
| 1292 | − struct nf_conntrack_tuple master; | |
| 1293 | − struct nf_conntrack_tuple_hash *master_h = NULL; | |
| 1294 | − struct nf_conn *master_ct = NULL; | |
| 1295 | − | |
| 1296 | − if (cda[CTA_TUPLE_MASTER]) { | |
| 1297 | − err = ctnetlink_parse_tuple(cda, | |
| 1298 | − &master, | |
| 1299 | − CTA_TUPLE_MASTER, | |
| 1300 | − u3); | |
| 1301 | − if (err < 0) | |
| 1302 | − goto out_unlock; | |
| 1298 | + err = -ENOENT; | |
| 1299 | + if (nlh->nlmsg_flags & NLM_F_CREATE) { | |
| 1300 | + struct nf_conn *ct; | |
| 1303 | 1301 | |
| 1304 | − master_h = __nf_conntrack_find(&init_net, &master); | |
| 1305 | − if (master_h == NULL) { | |
| 1306 | − err = -ENOENT; | |
| 1302 | + ct = ctnetlink_create_conntrack(cda, &otuple, | |
| 1303 | + &rtuple, u3); | |
| 1304 | + if (IS_ERR(ct)) { | |
| 1305 | + err = PTR_ERR(ct); | |
| 1307 | 1306 | goto out_unlock; |
| 1308 | 1307 | } |
| 1309 | − master_ct = nf_ct_tuplehash_to_ctrack(master_h); | |
| 1310 | − nf_conntrack_get(&master_ct->ct_general); | |
| 1311 | − } | |
| 1312 | − | |
| 1313 | − err = -ENOENT; | |
| 1314 | − if (nlh->nlmsg_flags & NLM_F_CREATE) | |
| 1315 | − err = ctnetlink_create_conntrack(cda, | |
| 1316 | − &otuple, | |
| 1317 | − &rtuple, | |
| 1318 | − master_ct, | |
| 1319 | − NETLINK_CB(skb).pid, | |
| 1320 | − nlmsg_report(nlh)); | |
| 1321 | − spin_unlock_bh(&nf_conntrack_lock); | |
| 1322 | − if (err < 0 && master_ct) | |
| 1323 | − nf_ct_put(master_ct); | |
| 1308 | + err = 0; | |
| 1309 | + nf_conntrack_get(&ct->ct_general); | |
| 1310 | + spin_unlock_bh(&nf_conntrack_lock); | |
| 1311 | + ctnetlink_event_report(ct, | |
| 1312 | + NETLINK_CB(skb).pid, | |
| 1313 | + nlmsg_report(nlh)); | |
| 1314 | + nf_ct_put(ct); | |
| 1315 | + } else | |
| 1316 | + spin_unlock_bh(&nf_conntrack_lock); | |
| 1324 | 1317 | |
| 1325 | 1318 | return err; |
| 1326 | 1319 | } |
| @@ -1332,17 +1325,6 @@ ctnetlink_new_conntrack(struct sock *ctnl, struct sk_buff *skb, · 5 unmodified lines | ||
| 1332 | 1325 | if (!(nlh->nlmsg_flags & NLM_F_EXCL)) { |
| 1333 | 1326 | struct nf_conn *ct = nf_ct_tuplehash_to_ctrack(h); |
| 1334 | 1327 | |
| 1335 | − /* we only allow nat config for new conntracks */ | |
| 1336 | − if (cda[CTA_NAT_SRC] || cda[CTA_NAT_DST]) { | |
| 1337 | − err = -EOPNOTSUPP; | |
| 1338 | − goto out_unlock; | |
| 1339 | − } | |
| 1340 | − /* can't link an existing conntrack to a master */ | |
| 1341 | − if (cda[CTA_TUPLE_MASTER]) { | |
| 1342 | − err = -EOPNOTSUPP; | |
| 1343 | − goto out_unlock; | |
| 1344 | − } | |
| 1345 | − | |
| 1346 | 1328 | err = ctnetlink_change_conntrack(ct, cda); |
| 1347 | 1329 | if (err == 0) { |
| 1348 | 1330 | nf_conntrack_get(&ct->ct_general); |
| @@ -1533,6 +1515,7 @@ static int ctnetlink_expect_event(struct notifier_block *this, · 184 unmodified lines | ||
| 1533 | 1515 | nla_put_failure: |
| 1534 | 1516 | rcu_read_unlock(); |
| 1535 | 1517 | nlmsg_failure: |
| 1518 | + nfnetlink_set_err(0, 0, -ENOBUFS); | |
| 1536 | 1519 | kfree_skb(skb); |
| 1537 | 1520 | return NOTIFY_DONE; |
| 1538 | 1521 | } |
| @@ -74,27 +74,6 @@ EXPORT_SYMBOL_GPL(__nf_ct_l4proto_find); · 73 unmodified lines | ||
| 74 | 74 | |
| 75 | 75 | /* this is guaranteed to always return a valid protocol helper, since |
| 76 | 76 | * it falls back to generic_protocol */ |
| 77 | −struct nf_conntrack_l4proto * | |
| 78 | −nf_ct_l4proto_find_get(u_int16_t l3proto, u_int8_t l4proto) | |
| 79 | −{ | |
| 80 | − struct nf_conntrack_l4proto *p; | |
| 81 | − | |
| 82 | − rcu_read_lock(); | |
| 83 | − p = __nf_ct_l4proto_find(l3proto, l4proto); | |
| 84 | − if (!try_module_get(p->me)) | |
| 85 | − p = &nf_conntrack_l4proto_generic; | |
| 86 | − rcu_read_unlock(); | |
| 87 | − | |
| 88 | − return p; | |
| 89 | −} | |
| 90 | −EXPORT_SYMBOL_GPL(nf_ct_l4proto_find_get); | |
| 91 | − | |
| 92 | −void nf_ct_l4proto_put(struct nf_conntrack_l4proto *p) | |
| 93 | −{ | |
| 94 | − module_put(p->me); | |
| 95 | −} | |
| 96 | −EXPORT_SYMBOL_GPL(nf_ct_l4proto_put); | |
| 97 | − | |
| 98 | 77 | struct nf_conntrack_l3proto * |
| 99 | 78 | nf_ct_l3proto_find_get(u_int16_t l3proto) |
| 100 | 79 | { |
| @@ -16,6 +16,9 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <linux/skbuff.h> |
| 17 | 17 | #include <linux/dccp.h> |
| 18 | 18 | |
| 19 | +#include <net/net_namespace.h> | |
| 20 | +#include <net/netns/generic.h> | |
| 21 | + | |
| 19 | 22 | #include <linux/netfilter/nfnetlink_conntrack.h> |
| 20 | 23 | #include <net/netfilter/nf_conntrack.h> |
| 21 | 24 | #include <net/netfilter/nf_conntrack_l4proto.h> |
| @@ -23,8 +26,6 @@ · 1 unmodified line | ||
| 23 | 26 | |
| 24 | 27 | static DEFINE_RWLOCK(dccp_lock); |
| 25 | 28 | |
| 26 | −static int nf_ct_dccp_loose __read_mostly = 1; | |
| 27 | − | |
| 28 | 29 | /* Timeouts are based on values from RFC4340: |
| 29 | 30 | * |
| 30 | 31 | * - REQUEST: |
| @@ -72,16 +73,6 @@ static int nf_ct_dccp_loose __read_mostly = 1; · 41 unmodified lines | ||
| 72 | 73 | |
| 73 | 74 | #define DCCP_MSL (2 * 60 * HZ) |
| 74 | 75 | |
| 75 | −static unsigned int dccp_timeout[CT_DCCP_MAX + 1] __read_mostly = { | |
| 76 | − [CT_DCCP_REQUEST] = 2 * DCCP_MSL, | |
| 77 | − [CT_DCCP_RESPOND] = 4 * DCCP_MSL, | |
| 78 | − [CT_DCCP_PARTOPEN] = 4 * DCCP_MSL, | |
| 79 | − [CT_DCCP_OPEN] = 12 * 3600 * HZ, | |
| 80 | − [CT_DCCP_CLOSEREQ] = 64 * HZ, | |
| 81 | − [CT_DCCP_CLOSING] = 64 * HZ, | |
| 82 | − [CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL, | |
| 83 | −}; | |
| 84 | − | |
| 85 | 76 | static const char * const dccp_state_names[] = { |
| 86 | 77 | [CT_DCCP_NONE] = "NONE", |
| 87 | 78 | [CT_DCCP_REQUEST] = "REQUEST", |
| @@ -393,6 +384,22 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = · 305 unmodified lines | ||
| 393 | 384 | }, |
| 394 | 385 | }; |
| 395 | 386 | |
| 387 | +/* this module per-net specifics */ | |
| 388 | +static int dccp_net_id; | |
| 389 | +struct dccp_net { | |
| 390 | + int dccp_loose; | |
| 391 | + unsigned int dccp_timeout[CT_DCCP_MAX + 1]; | |
| 392 | +#ifdef CONFIG_SYSCTL | |
| 393 | + struct ctl_table_header *sysctl_header; | |
| 394 | + struct ctl_table *sysctl_table; | |
| 395 | +#endif | |
| 396 | +}; | |
| 397 | + | |
| 398 | +static inline struct dccp_net *dccp_pernet(struct net *net) | |
| 399 | +{ | |
| 400 | + return net_generic(net, dccp_net_id); | |
| 401 | +} | |
| 402 | + | |
| 396 | 403 | static bool dccp_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff, |
| 397 | 404 | struct nf_conntrack_tuple *tuple) |
| 398 | 405 | { |
| @@ -419,6 +426,7 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, · 20 unmodified lines | ||
| 419 | 426 | unsigned int dataoff) |
| 420 | 427 | { |
| 421 | 428 | struct net *net = nf_ct_net(ct); |
| 429 | + struct dccp_net *dn; | |
| 422 | 430 | struct dccp_hdr _dh, *dh; |
| 423 | 431 | const char *msg; |
| 424 | 432 | u_int8_t state; |
| @@ -429,7 +437,8 @@ static bool dccp_new(struct nf_conn *ct, const struct sk_buff *skb, · 4 unmodified lines | ||
| 429 | 437 | state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE]; |
| 430 | 438 | switch (state) { |
| 431 | 439 | default: |
| 432 | − if (nf_ct_dccp_loose == 0) { | |
| 440 | + dn = dccp_pernet(net); | |
| 441 | + if (dn->dccp_loose == 0) { | |
| 433 | 442 | msg = "nf_ct_dccp: not picking up existing connection "; |
| 434 | 443 | goto out_invalid; |
| 435 | 444 | } |
| @@ -465,6 +474,7 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, · 29 unmodified lines | ||
| 465 | 474 | u_int8_t pf, unsigned int hooknum) |
| 466 | 475 | { |
| 467 | 476 | struct net *net = nf_ct_net(ct); |
| 477 | + struct dccp_net *dn; | |
| 468 | 478 | enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo); |
| 469 | 479 | struct dccp_hdr _dh, *dh; |
| 470 | 480 | u_int8_t type, old_state, new_state; |
| @@ -542,7 +552,9 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb, · 71 unmodified lines | ||
| 542 | 552 | ct->proto.dccp.last_pkt = type; |
| 543 | 553 | ct->proto.dccp.state = new_state; |
| 544 | 554 | write_unlock_bh(&dccp_lock); |
| 545 | − nf_ct_refresh_acct(ct, ctinfo, skb, dccp_timeout[new_state]); | |
| 555 | + | |
| 556 | + dn = dccp_pernet(net); | |
| 557 | + nf_ct_refresh_acct(ct, ctinfo, skb, dn->dccp_timeout[new_state]); | |
| 546 | 558 | |
| 547 | 559 | return NF_ACCEPT; |
| 548 | 560 | } |
| @@ -660,13 +672,11 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct) · 111 unmodified lines | ||
| 660 | 672 | #endif |
| 661 | 673 | |
| 662 | 674 | #ifdef CONFIG_SYSCTL |
| 663 | −static unsigned int dccp_sysctl_table_users; | |
| 664 | −static struct ctl_table_header *dccp_sysctl_header; | |
| 665 | −static ctl_table dccp_sysctl_table[] = { | |
| 675 | +/* template, data assigned later */ | |
| 676 | +static struct ctl_table dccp_sysctl_table[] = { | |
| 666 | 677 | { |
| 667 | 678 | .ctl_name = CTL_UNNUMBERED, |
| 668 | 679 | .procname = "nf_conntrack_dccp_timeout_request", |
| 669 | − .data = &dccp_timeout[CT_DCCP_REQUEST], | |
| 670 | 680 | .maxlen = sizeof(unsigned int), |
| 671 | 681 | .mode = 0644, |
| 672 | 682 | .proc_handler = proc_dointvec_jiffies, |
| @@ -674,7 +684,6 @@ static ctl_table dccp_sysctl_table[] = { · 1 unmodified line | ||
| 674 | 684 | { |
| 675 | 685 | .ctl_name = CTL_UNNUMBERED, |
| 676 | 686 | .procname = "nf_conntrack_dccp_timeout_respond", |
| 677 | − .data = &dccp_timeout[CT_DCCP_RESPOND], | |
| 678 | 687 | .maxlen = sizeof(unsigned int), |
| 679 | 688 | .mode = 0644, |
| 680 | 689 | .proc_handler = proc_dointvec_jiffies, |
| @@ -682,7 +691,6 @@ static ctl_table dccp_sysctl_table[] = { · 1 unmodified line | ||
| 682 | 691 | { |
| 683 | 692 | .ctl_name = CTL_UNNUMBERED, |
| 684 | 693 | .procname = "nf_conntrack_dccp_timeout_partopen", |
| 685 | − .data = &dccp_timeout[CT_DCCP_PARTOPEN], | |
| 686 | 694 | .maxlen = sizeof(unsigned int), |
| 687 | 695 | .mode = 0644, |
| 688 | 696 | .proc_handler = proc_dointvec_jiffies, |
| @@ -690,7 +698,6 @@ static ctl_table dccp_sysctl_table[] = { · 1 unmodified line | ||
| 690 | 698 | { |
| 691 | 699 | .ctl_name = CTL_UNNUMBERED, |
| 692 | 700 | .procname = "nf_conntrack_dccp_timeout_open", |
| 693 | − .data = &dccp_timeout[CT_DCCP_OPEN], | |
| 694 | 701 | .maxlen = sizeof(unsigned int), |
| 695 | 702 | .mode = 0644, |
| 696 | 703 | .proc_handler = proc_dointvec_jiffies, |
| @@ -698,7 +705,6 @@ static ctl_table dccp_sysctl_table[] = { · 1 unmodified line | ||
| 698 | 705 | { |
| 699 | 706 | .ctl_name = CTL_UNNUMBERED, |
| 700 | 707 | .procname = "nf_conntrack_dccp_timeout_closereq", |
| 701 | − .data = &dccp_timeout[CT_DCCP_CLOSEREQ], | |
| 702 | 708 | .maxlen = sizeof(unsigned int), |
| 703 | 709 | .mode = 0644, |
| 704 | 710 | .proc_handler = proc_dointvec_jiffies, |
| @@ -706,7 +712,6 @@ static ctl_table dccp_sysctl_table[] = { · 1 unmodified line | ||
| 706 | 712 | { |
| 707 | 713 | .ctl_name = CTL_UNNUMBERED, |
| 708 | 714 | .procname = "nf_conntrack_dccp_timeout_closing", |
| 709 | − .data = &dccp_timeout[CT_DCCP_CLOSING], | |
| 710 | 715 | .maxlen = sizeof(unsigned int), |
| 711 | 716 | .mode = 0644, |
| 712 | 717 | .proc_handler = proc_dointvec_jiffies, |
| @@ -714,7 +719,6 @@ static ctl_table dccp_sysctl_table[] = { · 1 unmodified line | ||
| 714 | 719 | { |
| 715 | 720 | .ctl_name = CTL_UNNUMBERED, |
| 716 | 721 | .procname = "nf_conntrack_dccp_timeout_timewait", |
| 717 | − .data = &dccp_timeout[CT_DCCP_TIMEWAIT], | |
| 718 | 722 | .maxlen = sizeof(unsigned int), |
| 719 | 723 | .mode = 0644, |
| 720 | 724 | .proc_handler = proc_dointvec_jiffies, |
| @@ -722,8 +726,7 @@ static ctl_table dccp_sysctl_table[] = { · 1 unmodified line | ||
| 722 | 726 | { |
| 723 | 727 | .ctl_name = CTL_UNNUMBERED, |
| 724 | 728 | .procname = "nf_conntrack_dccp_loose", |
| 725 | − .data = &nf_ct_dccp_loose, | |
| 726 | − .maxlen = sizeof(nf_ct_dccp_loose), | |
| 729 | + .maxlen = sizeof(int), | |
| 727 | 730 | .mode = 0644, |
| 728 | 731 | .proc_handler = proc_dointvec, |
| 729 | 732 | }, |
| @@ -751,11 +754,6 @@ static struct nf_conntrack_l4proto dccp_proto4 __read_mostly = { · 21 unmodified lines | ||
| 751 | 754 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
| 752 | 755 | .nla_policy = nf_ct_port_nla_policy, |
| 753 | 756 | #endif |
| 754 | −#ifdef CONFIG_SYSCTL | |
| 755 | − .ctl_table_users = &dccp_sysctl_table_users, | |
| 756 | − .ctl_table_header = &dccp_sysctl_header, | |
| 757 | − .ctl_table = dccp_sysctl_table, | |
| 758 | −#endif | |
| 759 | 757 | }; |
| 760 | 758 | |
| 761 | 759 | static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { |
| @@ -776,34 +774,107 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = { · 14 unmodified lines | ||
| 776 | 774 | .nlattr_to_tuple = nf_ct_port_nlattr_to_tuple, |
| 777 | 775 | .nla_policy = nf_ct_port_nla_policy, |
| 778 | 776 | #endif |
| 777 | +}; | |
| 778 | + | |
| 779 | +static __net_init int dccp_net_init(struct net *net) | |
| 780 | +{ | |
| 781 | + struct dccp_net *dn; | |
| 782 | + int err; | |
| 783 | + | |
| 784 | + dn = kmalloc(sizeof(*dn), GFP_KERNEL); | |
| 785 | + if (!dn) | |
| 786 | + return -ENOMEM; | |
| 787 | + | |
| 788 | + /* default values */ | |
| 789 | + dn->dccp_loose = 1; | |
| 790 | + dn->dccp_timeout[CT_DCCP_REQUEST] = 2 * DCCP_MSL; | |
| 791 | + dn->dccp_timeout[CT_DCCP_RESPOND] = 4 * DCCP_MSL; | |
| 792 | + dn->dccp_timeout[CT_DCCP_PARTOPEN] = 4 * DCCP_MSL; | |
| 793 | + dn->dccp_timeout[CT_DCCP_OPEN] = 12 * 3600 * HZ; | |
| 794 | + dn->dccp_timeout[CT_DCCP_CLOSEREQ] = 64 * HZ; | |
| 795 | + dn->dccp_timeout[CT_DCCP_CLOSING] = 64 * HZ; | |
| 796 | + dn->dccp_timeout[CT_DCCP_TIMEWAIT] = 2 * DCCP_MSL; | |
| 797 | + | |
| 798 | + err = net_assign_generic(net, dccp_net_id, dn); | |
| 799 | + if (err) | |
| 800 | + goto out; | |
| 801 | + | |
| 779 | 802 | #ifdef CONFIG_SYSCTL |
| 780 | − .ctl_table_users = &dccp_sysctl_table_users, | |
| 781 | − .ctl_table_header = &dccp_sysctl_header, | |
| 782 | − .ctl_table = dccp_sysctl_table, | |
| 803 | + err = -ENOMEM; | |
| 804 | + dn->sysctl_table = kmemdup(dccp_sysctl_table, | |
| 805 | + sizeof(dccp_sysctl_table), GFP_KERNEL); | |
| 806 | + if (!dn->sysctl_table) | |
| 807 | + goto out; | |
| 808 | + | |
| 809 | + dn->sysctl_table[0].data = &dn->dccp_timeout[CT_DCCP_REQUEST]; | |
| 810 | + dn->sysctl_table[1].data = &dn->dccp_timeout[CT_DCCP_RESPOND]; | |
| 811 | + dn->sysctl_table[2].data = &dn->dccp_timeout[CT_DCCP_PARTOPEN]; | |
| 812 | + dn->sysctl_table[3].data = &dn->dccp_timeout[CT_DCCP_OPEN]; | |
| 813 | + dn->sysctl_table[4].data = &dn->dccp_timeout[CT_DCCP_CLOSEREQ]; | |
| 814 | + dn->sysctl_table[5].data = &dn->dccp_timeout[CT_DCCP_CLOSING]; | |
| 815 | + dn->sysctl_table[6].data = &dn->dccp_timeout[CT_DCCP_TIMEWAIT]; | |
| 816 | + dn->sysctl_table[7].data = &dn->dccp_loose; | |
| 817 | + | |
| 818 | + dn->sysctl_header = register_net_sysctl_table(net, | |
| 819 | + nf_net_netfilter_sysctl_path, dn->sysctl_table); | |
| 820 | + if (!dn->sysctl_header) { | |
| 821 | + kfree(dn->sysctl_table); | |
| 822 | + goto out; | |
| 823 | + } | |
| 783 | 824 | #endif |
| 825 | + | |
| 826 | + return 0; | |
| 827 | + | |
| 828 | +out: | |
| 829 | + kfree(dn); | |
| 830 | + return err; | |
| 831 | +} | |
| 832 | + | |
| 833 | +static __net_exit void dccp_net_exit(struct net *net) | |
| 834 | +{ | |
| 835 | + struct dccp_net *dn = dccp_pernet(net); | |
| 836 | +#ifdef CONFIG_SYSCTL | |
| 837 | + unregister_net_sysctl_table(dn->sysctl_header); | |
| 838 | + kfree(dn->sysctl_table); | |
| 839 | +#endif | |
| 840 | + kfree(dn); | |
| 841 | + | |
| 842 | + net_assign_generic(net, dccp_net_id, NULL); | |
| 843 | +} | |
| 844 | + | |
| 845 | +static struct pernet_operations dccp_net_ops = { | |
| 846 | + .init = dccp_net_init, | |
| 847 | + .exit = dccp_net_exit, | |
| 784 | 848 | }; |
| 785 | 849 | |
| 786 | 850 | static int __init nf_conntrack_proto_dccp_init(void) |
| 787 | 851 | { |
| 788 | 852 | int err; |
| 789 | 853 | |
| 790 | − err = nf_conntrack_l4proto_register(&dccp_proto4); | |
| 854 | + err = register_pernet_gen_subsys(&dccp_net_id, &dccp_net_ops); | |
| 791 | 855 | if (err < 0) |
| 792 | 856 | goto err1; |
| 793 | 857 | |
| 794 | − err = nf_conntrack_l4proto_register(&dccp_proto6); | |
| 858 | + err = nf_conntrack_l4proto_register(&dccp_proto4); | |
| 795 | 859 | if (err < 0) |
| 796 | 860 | goto err2; |
| 861 | + | |
| 862 | + err = nf_conntrack_l4proto_register(&dccp_proto6); | |
| 863 | + if (err < 0) | |
| 864 | + goto err3; | |
| 797 | 865 | return 0; |
| 798 | 866 | |
| 799 | −err2: | |
| 867 | +err3: | |
| 800 | 868 | nf_conntrack_l4proto_unregister(&dccp_proto4); |
| 869 | +err2: | |
| 870 | + unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops); | |
| 801 | 871 | err1: |
| 802 | 872 | return err; |
| 803 | 873 | } |
| 804 | 874 | |
| 805 | 875 | static void __exit nf_conntrack_proto_dccp_fini(void) |
| 806 | 876 | { |
| 877 | + unregister_pernet_gen_subsys(dccp_net_id, &dccp_net_ops); | |
| 807 | 878 | nf_conntrack_l4proto_unregister(&dccp_proto6); |
| 808 | 879 | nf_conntrack_l4proto_unregister(&dccp_proto4); |
| 809 | 880 | } |
| @@ -92,7 +92,7 @@ static struct ctl_table generic_compat_sysctl_table[] = { · 91 unmodified lines | ||
| 92 | 92 | struct nf_conntrack_l4proto nf_conntrack_l4proto_generic __read_mostly = |
| 93 | 93 | { |
| 94 | 94 | .l3proto = PF_UNSPEC, |
| 95 | − .l4proto = 0, | |
| 95 | + .l4proto = 255, | |
| 96 | 96 | .name = "unknown", |
| 97 | 97 | .pkt_to_tuple = generic_pkt_to_tuple, |
| 98 | 98 | .invert_tuple = generic_invert_tuple, |
| @@ -25,6 +25,8 @@ · 24 unmodified lines | ||
| 25 | 25 | #include <net/netfilter/nf_conntrack_l4proto.h> |
| 26 | 26 | #include <net/netfilter/nf_conntrack_ecache.h> |
| 27 | 27 | #include <net/netfilter/nf_log.h> |
| 28 | +#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | |
| 29 | +#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | |
| 28 | 30 | |
| 29 | 31 | /* Protects ct->proto.tcp */ |
| 30 | 32 | static DEFINE_RWLOCK(tcp_lock); |
| @@ -22,6 +22,8 @@ · 21 unmodified lines | ||
| 22 | 22 | #include <net/netfilter/nf_conntrack_l4proto.h> |
| 23 | 23 | #include <net/netfilter/nf_conntrack_ecache.h> |
| 24 | 24 | #include <net/netfilter/nf_log.h> |
| 25 | +#include <net/netfilter/ipv4/nf_conntrack_ipv4.h> | |
| 26 | +#include <net/netfilter/ipv6/nf_conntrack_ipv6.h> | |
| 25 | 27 | |
| 26 | 28 | static unsigned int nf_ct_udp_timeout __read_mostly = 30*HZ; |
| 27 | 29 | static unsigned int nf_ct_udp_timeout_stream __read_mostly = 180*HZ; |
| @@ -14,58 +14,63 @@ · 13 unmodified lines | ||
| 14 | 14 | LOG target modules */ |
| 15 | 15 | |
| 16 | 16 | #define NF_LOG_PREFIXLEN 128 |
| 17 | +#define NFLOGGER_NAME_LEN 64 | |
| 17 | 18 | |
| 18 | 19 | static const struct nf_logger *nf_loggers[NFPROTO_NUMPROTO] __read_mostly; |
| 20 | +static struct list_head nf_loggers_l[NFPROTO_NUMPROTO] __read_mostly; | |
| 19 | 21 | static DEFINE_MUTEX(nf_log_mutex); |
| 20 | 22 | |
| 21 | −/* return EBUSY if somebody else is registered, EEXIST if the same logger | |
| 22 | − * is registred, 0 on success. */ | |
| 23 | −int nf_log_register(u_int8_t pf, const struct nf_logger *logger) | |
| 23 | +static struct nf_logger *__find_logger(int pf, const char *str_logger) | |
| 24 | 24 | { |
| 25 | − int ret; | |
| 25 | + struct nf_logger *t; | |
| 26 | 26 | |
| 27 | − if (pf >= ARRAY_SIZE(nf_loggers)) | |
| 28 | − return -EINVAL; | |
| 29 | − | |
| 30 | − /* Any setup of logging members must be done before | |
| 31 | − * substituting pointer. */ | |
| 32 | − ret = mutex_lock_interruptible(&nf_log_mutex); | |
| 33 | − if (ret < 0) | |
| 34 | − return ret; | |
| 35 | − | |
| 36 | − if (!nf_loggers[pf]) | |
| 37 | − rcu_assign_pointer(nf_loggers[pf], logger); | |
| 38 | − else if (nf_loggers[pf] == logger) | |
| 39 | − ret = -EEXIST; | |
| 40 | − else | |
| 41 | − ret = -EBUSY; | |
| 27 | + list_for_each_entry(t, &nf_loggers_l[pf], list[pf]) { | |
| 28 | + if (!strnicmp(str_logger, t->name, strlen(t->name))) | |
| 29 | + return t; | |
| 30 | + } | |
| 42 | 31 | |
| 43 | − mutex_unlock(&nf_log_mutex); | |
| 44 | − return ret; | |
| 32 | + return NULL; | |
| 45 | 33 | } |
| 46 | −EXPORT_SYMBOL(nf_log_register); | |
| 47 | 34 | |
| 48 | −void nf_log_unregister_pf(u_int8_t pf) | |
| 35 | +/* return EEXIST if the same logger is registred, 0 on success. */ | |
| 36 | +int nf_log_register(u_int8_t pf, struct nf_logger *logger) | |
| 49 | 37 | { |
| 38 | + const struct nf_logger *llog; | |
| 39 | + | |
| 50 | 40 | if (pf >= ARRAY_SIZE(nf_loggers)) |
| 51 | − return; | |
| 41 | + return -EINVAL; | |
| 42 | + | |
| 52 | 43 | mutex_lock(&nf_log_mutex); |
| 53 | − rcu_assign_pointer(nf_loggers[pf], NULL); | |
| 44 | + | |
| 45 | + if (pf == NFPROTO_UNSPEC) { | |
| 46 | + int i; | |
| 47 | + for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) | |
| 48 | + list_add_tail(&(logger->list[i]), &(nf_loggers_l[i])); | |
| 49 | + } else { | |
| 50 | + /* register at end of list to honor first register win */ | |
| 51 | + list_add_tail(&logger->list[pf], &nf_loggers_l[pf]); | |
| 52 | + llog = rcu_dereference(nf_loggers[pf]); | |
| 53 | + if (llog == NULL) | |
| 54 | + rcu_assign_pointer(nf_loggers[pf], logger); | |
| 55 | + } | |
| 56 | + | |
| 54 | 57 | mutex_unlock(&nf_log_mutex); |
| 55 | 58 | |
| 56 | − /* Give time to concurrent readers. */ | |
| 57 | − synchronize_rcu(); | |
| 59 | + return 0; | |
| 58 | 60 | } |
| 59 | −EXPORT_SYMBOL(nf_log_unregister_pf); | |
| 61 | +EXPORT_SYMBOL(nf_log_register); | |
| 60 | 62 | |
| 61 | −void nf_log_unregister(const struct nf_logger *logger) | |
| 63 | +void nf_log_unregister(struct nf_logger *logger) | |
| 62 | 64 | { |
| 65 | + const struct nf_logger *c_logger; | |
| 63 | 66 | int i; |
| 64 | 67 | |
| 65 | 68 | mutex_lock(&nf_log_mutex); |
| 66 | 69 | for (i = 0; i < ARRAY_SIZE(nf_loggers); i++) { |
| 67 | − if (nf_loggers[i] == logger) | |
| 70 | + c_logger = rcu_dereference(nf_loggers[i]); | |
| 71 | + if (c_logger == logger) | |
| 68 | 72 | rcu_assign_pointer(nf_loggers[i], NULL); |
| 73 | + list_del(&logger->list[i]); | |
| 69 | 74 | } |
| 70 | 75 | mutex_unlock(&nf_log_mutex); |
| 71 | 76 | |
| @@ -73,6 +78,27 @@ void nf_log_unregister(const struct nf_logger *logger) · 1 unmodified line | ||
| 73 | 78 | } |
| 74 | 79 | EXPORT_SYMBOL(nf_log_unregister); |
| 75 | 80 | |
| 81 | +int nf_log_bind_pf(u_int8_t pf, const struct nf_logger *logger) | |
| 82 | +{ | |
| 83 | + mutex_lock(&nf_log_mutex); | |
| 84 | + if (__find_logger(pf, logger->name) == NULL) { | |
| 85 | + mutex_unlock(&nf_log_mutex); | |
| 86 | + return -ENOENT; | |
| 87 | + } | |
| 88 | + rcu_assign_pointer(nf_loggers[pf], logger); | |
| 89 | + mutex_unlock(&nf_log_mutex); | |
| 90 | + return 0; | |
| 91 | +} | |
| 92 | +EXPORT_SYMBOL(nf_log_bind_pf); | |
| 93 | + | |
| 94 | +void nf_log_unbind_pf(u_int8_t pf) | |
| 95 | +{ | |
| 96 | + mutex_lock(&nf_log_mutex); | |
| 97 | + rcu_assign_pointer(nf_loggers[pf], NULL); | |
| 98 | + mutex_unlock(&nf_log_mutex); | |
| 99 | +} | |
| 100 | +EXPORT_SYMBOL(nf_log_unbind_pf); | |
| 101 | + | |
| 76 | 102 | void nf_log_packet(u_int8_t pf, |
| 77 | 103 | unsigned int hooknum, |
| 78 | 104 | const struct sk_buff *skb, |
| @@ -129,13 +155,37 @@ static int seq_show(struct seq_file *s, void *v) · 50 unmodified lines | ||
| 129 | 155 | { |
| 130 | 156 | loff_t *pos = v; |
| 131 | 157 | const struct nf_logger *logger; |
| 158 | + struct nf_logger *t; | |
| 159 | + int ret; | |
| 132 | 160 | |
| 133 | 161 | logger = rcu_dereference(nf_loggers[*pos]); |
| 134 | 162 | |
| 135 | 163 | if (!logger) |
| 136 | − return seq_printf(s, "%2lld NONE\n", *pos); | |
| 164 | + ret = seq_printf(s, "%2lld NONE (", *pos); | |
| 165 | + else | |
| 166 | + ret = seq_printf(s, "%2lld %s (", *pos, logger->name); | |
| 167 | + | |
| 168 | + if (ret < 0) | |
| 169 | + return ret; | |
| 170 | + | |
| 171 | + mutex_lock(&nf_log_mutex); | |
| 172 | + list_for_each_entry(t, &nf_loggers_l[*pos], list[*pos]) { | |
| 173 | + ret = seq_printf(s, "%s", t->name); | |
| 174 | + if (ret < 0) { | |
| 175 | + mutex_unlock(&nf_log_mutex); | |
| 176 | + return ret; | |
| 177 | + } | |
| 178 | + if (&t->list[*pos] != nf_loggers_l[*pos].prev) { | |
| 179 | + ret = seq_printf(s, ","); | |
| 180 | + if (ret < 0) { | |
| 181 | + mutex_unlock(&nf_log_mutex); | |
| 182 | + return ret; | |
| 183 | + } | |
| 184 | + } | |
| 185 | + } | |
| 186 | + mutex_unlock(&nf_log_mutex); | |
| 137 | 187 | |
| 138 | − return seq_printf(s, "%2lld %s\n", *pos, logger->name); | |
| 188 | + return seq_printf(s, ")\n"); | |
| 139 | 189 | } |
| 140 | 190 | |
| 141 | 191 | static const struct seq_operations nflog_seq_ops = { |
| @@ -158,15 +208,102 @@ static const struct file_operations nflog_file_ops = { · 16 unmodified lines | ||
| 158 | 208 | .release = seq_release, |
| 159 | 209 | }; |
| 160 | 210 | |
| 211 | + | |
| 161 | 212 | #endif /* PROC_FS */ |
| 162 | 213 | |
| 214 | +#ifdef CONFIG_SYSCTL | |
| 215 | +struct ctl_path nf_log_sysctl_path[] = { | |
| 216 | + { .procname = "net", .ctl_name = CTL_NET, }, | |
| 217 | + { .procname = "netfilter", .ctl_name = NET_NETFILTER, }, | |
| 218 | + { .procname = "nf_log", .ctl_name = CTL_UNNUMBERED, }, | |
| 219 | + { } | |
| 220 | +}; | |
| 221 | + | |
| 222 | +static char nf_log_sysctl_fnames[NFPROTO_NUMPROTO-NFPROTO_UNSPEC][3]; | |
| 223 | +static struct ctl_table nf_log_sysctl_table[NFPROTO_NUMPROTO+1]; | |
| 224 | +static struct ctl_table_header *nf_log_dir_header; | |
| 225 | + | |
| 226 | +static int nf_log_proc_dostring(ctl_table *table, int write, struct file *filp, | |
| 227 | + void *buffer, size_t *lenp, loff_t *ppos) | |
| 228 | +{ | |
| 229 | + const struct nf_logger *logger; | |
| 230 | + int r = 0; | |
| 231 | + int tindex = (unsigned long)table->extra1; | |
| 232 | + | |
| 233 | + if (write) { | |
| 234 | + if (!strcmp(buffer, "NONE")) { | |
| 235 | + nf_log_unbind_pf(tindex); | |
| 236 | + return 0; | |
| 237 | + } | |
| 238 | + mutex_lock(&nf_log_mutex); | |
| 239 | + logger = __find_logger(tindex, buffer); | |
| 240 | + if (logger == NULL) { | |
| 241 | + mutex_unlock(&nf_log_mutex); | |
| 242 | + return -ENOENT; | |
| 243 | + } | |
| 244 | + rcu_assign_pointer(nf_loggers[tindex], logger); | |
| 245 | + mutex_unlock(&nf_log_mutex); | |
| 246 | + } else { | |
| 247 | + rcu_read_lock(); | |
| 248 | + logger = rcu_dereference(nf_loggers[tindex]); | |
| 249 | + if (!logger) | |
| 250 | + table->data = "NONE"; | |
| 251 | + else | |
| 252 | + table->data = logger->name; | |
| 253 | + r = proc_dostring(table, write, filp, buffer, lenp, ppos); | |
| 254 | + rcu_read_unlock(); | |
| 255 | + } | |
| 256 | + | |
| 257 | + return r; | |
| 258 | +} | |
| 259 | + | |
| 260 | +static __init int netfilter_log_sysctl_init(void) | |
| 261 | +{ | |
| 262 | + int i; | |
| 263 | + | |
| 264 | + for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) { | |
| 265 | + snprintf(nf_log_sysctl_fnames[i-NFPROTO_UNSPEC], 3, "%d", i); | |
| 266 | + nf_log_sysctl_table[i].ctl_name = CTL_UNNUMBERED; | |
| 267 | + nf_log_sysctl_table[i].procname = | |
| 268 | + nf_log_sysctl_fnames[i-NFPROTO_UNSPEC]; | |
| 269 | + nf_log_sysctl_table[i].data = NULL; | |
| 270 | + nf_log_sysctl_table[i].maxlen = | |
| 271 | + NFLOGGER_NAME_LEN * sizeof(char); | |
| 272 | + nf_log_sysctl_table[i].mode = 0644; | |
| 273 | + nf_log_sysctl_table[i].proc_handler = nf_log_proc_dostring; | |
| 274 | + nf_log_sysctl_table[i].extra1 = (void *)(unsigned long) i; | |
| 275 | + } | |
| 276 | + | |
| 277 | + nf_log_dir_header = register_sysctl_paths(nf_log_sysctl_path, | |
| 278 | + nf_log_sysctl_table); | |
| 279 | + if (!nf_log_dir_header) | |
| 280 | + return -ENOMEM; | |
| 281 | + | |
| 282 | + return 0; | |
| 283 | +} | |
| 284 | +#else | |
| 285 | +static __init int netfilter_log_sysctl_init(void) | |
| 286 | +{ | |
| 287 | + return 0; | |
| 288 | +} | |
| 289 | +#endif /* CONFIG_SYSCTL */ | |
| 163 | 290 | |
| 164 | 291 | int __init netfilter_log_init(void) |
| 165 | 292 | { |
| 293 | + int i, r; | |
| 166 | 294 | #ifdef CONFIG_PROC_FS |
| 167 | 295 | if (!proc_create("nf_log", S_IRUGO, |
| 168 | 296 | proc_net_netfilter, &nflog_file_ops)) |
| 169 | 297 | return -1; |
| 170 | 298 | #endif |
| 299 | + | |
| 300 | + /* Errors will trigger panic, unroll on error is unnecessary. */ | |
| 301 | + r = netfilter_log_sysctl_init(); | |
| 302 | + if (r < 0) | |
| 303 | + return r; | |
| 304 | + | |
| 305 | + for (i = NFPROTO_UNSPEC; i < NFPROTO_NUMPROTO; i++) | |
| 306 | + INIT_LIST_HEAD(&(nf_loggers_l[i])); | |
| 307 | + | |
| 171 | 308 | return 0; |
| 172 | 309 | } |
| @@ -113,6 +113,12 @@ int nfnetlink_send(struct sk_buff *skb, u32 pid, unsigned group, int echo) · 112 unmodified lines | ||
| 113 | 113 | } |
| 114 | 114 | EXPORT_SYMBOL_GPL(nfnetlink_send); |
| 115 | 115 | |
| 116 | +void nfnetlink_set_err(u32 pid, u32 group, int error) | |
| 117 | +{ | |
| 118 | + netlink_set_err(nfnl, pid, group, error); | |
| 119 | +} | |
| 120 | +EXPORT_SYMBOL_GPL(nfnetlink_set_err); | |
| 121 | + | |
| 116 | 122 | int nfnetlink_unicast(struct sk_buff *skb, u_int32_t pid, int flags) |
| 117 | 123 | { |
| 118 | 124 | return netlink_unicast(nfnl, skb, pid, flags); |
| @@ -693,7 +693,7 @@ nfulnl_recv_unsupp(struct sock *ctnl, struct sk_buff *skb, · 692 unmodified lines | ||
| 693 | 693 | return -ENOTSUPP; |
| 694 | 694 | } |
| 695 | 695 | |
| 696 | −static const struct nf_logger nfulnl_logger = { | |
| 696 | +static struct nf_logger nfulnl_logger __read_mostly = { | |
| 697 | 697 | .name = "nfnetlink_log", |
| 698 | 698 | .logfn = &nfulnl_log_packet, |
| 699 | 699 | .me = THIS_MODULE, |
| @@ -725,9 +725,9 @@ nfulnl_recv_config(struct sock *ctnl, struct sk_buff *skb, · 25 unmodified lines | ||
| 725 | 725 | /* Commands without queue context */ |
| 726 | 726 | switch (cmd->command) { |
| 727 | 727 | case NFULNL_CFG_CMD_PF_BIND: |
| 728 | − return nf_log_register(pf, &nfulnl_logger); | |
| 728 | + return nf_log_bind_pf(pf, &nfulnl_logger); | |
| 729 | 729 | case NFULNL_CFG_CMD_PF_UNBIND: |
| 730 | − nf_log_unregister_pf(pf); | |
| 730 | + nf_log_unbind_pf(pf); | |
| 731 | 731 | return 0; |
| 732 | 732 | } |
| 733 | 733 | } |
| @@ -952,17 +952,25 @@ static int __init nfnetlink_log_init(void) · 218 unmodified lines | ||
| 952 | 952 | goto cleanup_netlink_notifier; |
| 953 | 953 | } |
| 954 | 954 | |
| 955 | + status = nf_log_register(NFPROTO_UNSPEC, &nfulnl_logger); | |
| 956 | + if (status < 0) { | |
| 957 | + printk(KERN_ERR "log: failed to register logger\n"); | |
| 958 | + goto cleanup_subsys; | |
| 959 | + } | |
| 960 | + | |
| 955 | 961 | #ifdef CONFIG_PROC_FS |
| 956 | 962 | if (!proc_create("nfnetlink_log", 0440, |
| 957 | 963 | proc_net_netfilter, &nful_file_ops)) |
| 958 | − goto cleanup_subsys; | |
| 964 | + goto cleanup_logger; | |
| 959 | 965 | #endif |
| 960 | 966 | return status; |
| 961 | 967 | |
| 962 | 968 | #ifdef CONFIG_PROC_FS |
| 969 | +cleanup_logger: | |
| 970 | + nf_log_unregister(&nfulnl_logger); | |
| 971 | +#endif | |
| 963 | 972 | cleanup_subsys: |
| 964 | 973 | nfnetlink_subsys_unregister(&nfulnl_subsys); |
| 965 | −#endif | |
| 966 | 974 | cleanup_netlink_notifier: |
| 967 | 975 | netlink_unregister_notifier(&nfulnl_rtnl_notifier); |
| 968 | 976 | return status; |
| @@ -625,6 +625,20 @@ void xt_free_table_info(struct xt_table_info *info) · 624 unmodified lines | ||
| 625 | 625 | } |
| 626 | 626 | EXPORT_SYMBOL(xt_free_table_info); |
| 627 | 627 | |
| 628 | +void xt_table_entry_swap_rcu(struct xt_table_info *oldinfo, | |
| 629 | + struct xt_table_info *newinfo) | |
| 630 | +{ | |
| 631 | + unsigned int cpu; | |
| 632 | + | |
| 633 | + for_each_possible_cpu(cpu) { | |
| 634 | + void *p = oldinfo->entries[cpu]; | |
| 635 | + rcu_assign_pointer(oldinfo->entries[cpu], newinfo->entries[cpu]); | |
| 636 | + newinfo->entries[cpu] = p; | |
| 637 | + } | |
| 638 | + | |
| 639 | +} | |
| 640 | +EXPORT_SYMBOL_GPL(xt_table_entry_swap_rcu); | |
| 641 | + | |
| 628 | 642 | /* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */ |
| 629 | 643 | struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af, |
| 630 | 644 | const char *name) |
| @@ -671,21 +685,22 @@ xt_replace_table(struct xt_table *table, · 40 unmodified lines | ||
| 671 | 685 | struct xt_table_info *oldinfo, *private; |
| 672 | 686 | |
| 673 | 687 | /* Do the substitution. */ |
| 674 | − write_lock_bh(&table->lock); | |
| 688 | + mutex_lock(&table->lock); | |
| 675 | 689 | private = table->private; |
| 676 | 690 | /* Check inside lock: is the old number correct? */ |
| 677 | 691 | if (num_counters != private->number) { |
| 678 | 692 | duprintf("num_counters != table->private->number (%u/%u)\n", |
| 679 | 693 | num_counters, private->number); |
| 680 | − write_unlock_bh(&table->lock); | |
| 694 | + mutex_unlock(&table->lock); | |
| 681 | 695 | *error = -EAGAIN; |
| 682 | 696 | return NULL; |
| 683 | 697 | } |
| 684 | 698 | oldinfo = private; |
| 685 | − table->private = newinfo; | |
| 699 | + rcu_assign_pointer(table->private, newinfo); | |
| 686 | 700 | newinfo->initial_entries = oldinfo->initial_entries; |
| 687 | − write_unlock_bh(&table->lock); | |
| 701 | + mutex_unlock(&table->lock); | |
| 688 | 702 | |
| 703 | + synchronize_net(); | |
| 689 | 704 | return oldinfo; |
| 690 | 705 | } |
| 691 | 706 | EXPORT_SYMBOL_GPL(xt_replace_table); |
| @@ -719,7 +734,8 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table *table, · 27 unmodified lines | ||
| 719 | 734 | |
| 720 | 735 | /* Simplifies replace_table code. */ |
| 721 | 736 | table->private = bootstrap; |
| 722 | − rwlock_init(&table->lock); | |
| 737 | + mutex_init(&table->lock); | |
| 738 | + | |
| 723 | 739 | if (!xt_replace_table(table, 0, newinfo, &ret)) |
| 724 | 740 | goto unlock; |
| 725 | 741 | |
| @@ -0,0 +1,171 @@ | ||
| 1 | +/* | |
| 2 | + * TTL modification target for IP tables | |
| 3 | + * (C) 2000,2005 by Harald Welte <laforge@netfilter.org> | |
| 4 | + * | |
| 5 | + * Hop Limit modification target for ip6tables | |
| 6 | + * Maciej Soltysiak <solt@dns.toxicfilms.tv> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify | |
| 9 | + * it under the terms of the GNU General Public License version 2 as | |
| 10 | + * published by the Free Software Foundation. | |
| 11 | + */ | |
| 12 | + | |
| 13 | +#include <linux/module.h> | |
| 14 | +#include <linux/skbuff.h> | |
| 15 | +#include <linux/ip.h> | |
| 16 | +#include <linux/ipv6.h> | |
| 17 | +#include <net/checksum.h> | |
| 18 | + | |
| 19 | +#include <linux/netfilter/x_tables.h> | |
| 20 | +#include <linux/netfilter_ipv4/ipt_TTL.h> | |
| 21 | +#include <linux/netfilter_ipv6/ip6t_HL.h> | |
| 22 | + | |
| 23 | +MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>"); | |
| 24 | +MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | |
| 25 | +MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target"); | |
| 26 | +MODULE_LICENSE("GPL"); | |
| 27 | + | |
| 28 | +static unsigned int | |
| 29 | +ttl_tg(struct sk_buff *skb, const struct xt_target_param *par) | |
| 30 | +{ | |
| 31 | + struct iphdr *iph; | |
| 32 | + const struct ipt_TTL_info *info = par->targinfo; | |
| 33 | + int new_ttl; | |
| 34 | + | |
| 35 | + if (!skb_make_writable(skb, skb->len)) | |
| 36 | + return NF_DROP; | |
| 37 | + | |
| 38 | + iph = ip_hdr(skb); | |
| 39 | + | |
| 40 | + switch (info->mode) { | |
| 41 | + case IPT_TTL_SET: | |
| 42 | + new_ttl = info->ttl; | |
| 43 | + break; | |
| 44 | + case IPT_TTL_INC: | |
| 45 | + new_ttl = iph->ttl + info->ttl; | |
| 46 | + if (new_ttl > 255) | |
| 47 | + new_ttl = 255; | |
| 48 | + break; | |
| 49 | + case IPT_TTL_DEC: | |
| 50 | + new_ttl = iph->ttl - info->ttl; | |
| 51 | + if (new_ttl < 0) | |
| 52 | + new_ttl = 0; | |
| 53 | + break; | |
| 54 | + default: | |
| 55 | + new_ttl = iph->ttl; | |
| 56 | + break; | |
| 57 | + } | |
| 58 | + | |
| 59 | + if (new_ttl != iph->ttl) { | |
| 60 | + csum_replace2(&iph->check, htons(iph->ttl << 8), | |
| 61 | + htons(new_ttl << 8)); | |
| 62 | + iph->ttl = new_ttl; | |
| 63 | + } | |
| 64 | + | |
| 65 | + return XT_CONTINUE; | |
| 66 | +} | |
| 67 | + | |
| 68 | +static unsigned int | |
| 69 | +hl_tg6(struct sk_buff *skb, const struct xt_target_param *par) | |
| 70 | +{ | |
| 71 | + struct ipv6hdr *ip6h; | |
| 72 | + const struct ip6t_HL_info *info = par->targinfo; | |
| 73 | + int new_hl; | |
| 74 | + | |
| 75 | + if (!skb_make_writable(skb, skb->len)) | |
| 76 | + return NF_DROP; | |
| 77 | + | |
| 78 | + ip6h = ipv6_hdr(skb); | |
| 79 | + | |
| 80 | + switch (info->mode) { | |
| 81 | + case IP6T_HL_SET: | |
| 82 | + new_hl = info->hop_limit; | |
| 83 | + break; | |
| 84 | + case IP6T_HL_INC: | |
| 85 | + new_hl = ip6h->hop_limit + info->hop_limit; | |
| 86 | + if (new_hl > 255) | |
| 87 | + new_hl = 255; | |
| 88 | + break; | |
| 89 | + case IP6T_HL_DEC: | |
| 90 | + new_hl = ip6h->hop_limit - info->hop_limit; | |
| 91 | + if (new_hl < 0) | |
| 92 | + new_hl = 0; | |
| 93 | + break; | |
| 94 | + default: | |
| 95 | + new_hl = ip6h->hop_limit; | |
| 96 | + break; | |
| 97 | + } | |
| 98 | + | |
| 99 | + ip6h->hop_limit = new_hl; | |
| 100 | + | |
| 101 | + return XT_CONTINUE; | |
| 102 | +} | |
| 103 | + | |
| 104 | +static bool ttl_tg_check(const struct xt_tgchk_param *par) | |
| 105 | +{ | |
| 106 | + const struct ipt_TTL_info *info = par->targinfo; | |
| 107 | + | |
| 108 | + if (info->mode > IPT_TTL_MAXMODE) { | |
| 109 | + printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n", | |
| 110 | + info->mode); | |
| 111 | + return false; | |
| 112 | + } | |
| 113 | + if (info->mode != IPT_TTL_SET && info->ttl == 0) | |
| 114 | + return false; | |
| 115 | + return true; | |
| 116 | +} | |
| 117 | + | |
| 118 | +static bool hl_tg6_check(const struct xt_tgchk_param *par) | |
| 119 | +{ | |
| 120 | + const struct ip6t_HL_info *info = par->targinfo; | |
| 121 | + | |
| 122 | + if (info->mode > IP6T_HL_MAXMODE) { | |
| 123 | + printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n", | |
| 124 | + info->mode); | |
| 125 | + return false; | |
| 126 | + } | |
| 127 | + if (info->mode != IP6T_HL_SET && info->hop_limit == 0) { | |
| 128 | + printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't " | |
| 129 | + "make sense with value 0\n"); | |
| 130 | + return false; | |
| 131 | + } | |
| 132 | + return true; | |
| 133 | +} | |
| 134 | + | |
| 135 | +static struct xt_target hl_tg_reg[] __read_mostly = { | |
| 136 | + { | |
| 137 | + .name = "TTL", | |
| 138 | + .revision = 0, | |
| 139 | + .family = NFPROTO_IPV4, | |
| 140 | + .target = ttl_tg, | |
| 141 | + .targetsize = sizeof(struct ipt_TTL_info), | |
| 142 | + .table = "mangle", | |
| 143 | + .checkentry = ttl_tg_check, | |
| 144 | + .me = THIS_MODULE, | |
| 145 | + }, | |
| 146 | + { | |
| 147 | + .name = "HL", | |
| 148 | + .revision = 0, | |
| 149 | + .family = NFPROTO_IPV6, | |
| 150 | + .target = hl_tg6, | |
| 151 | + .targetsize = sizeof(struct ip6t_HL_info), | |
| 152 | + .table = "mangle", | |
| 153 | + .checkentry = hl_tg6_check, | |
| 154 | + .me = THIS_MODULE, | |
| 155 | + }, | |
| 156 | +}; | |
| 157 | + | |
| 158 | +static int __init hl_tg_init(void) | |
| 159 | +{ | |
| 160 | + return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); | |
| 161 | +} | |
| 162 | + | |
| 163 | +static void __exit hl_tg_exit(void) | |
| 164 | +{ | |
| 165 | + xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg)); | |
| 166 | +} | |
| 167 | + | |
| 168 | +module_init(hl_tg_init); | |
| 169 | +module_exit(hl_tg_exit); | |
| 170 | +MODULE_ALIAS("ipt_TTL"); | |
| 171 | +MODULE_ALIAS("ip6t_HL"); | |
| @@ -0,0 +1,161 @@ | ||
| 1 | +/* | |
| 2 | + * xt_LED.c - netfilter target to make LEDs blink upon packet matches | |
| 3 | + * | |
| 4 | + * Copyright (C) 2008 Adam Nielsen <a.nielsen@shikadi.net> | |
| 5 | + * | |
| 6 | + * This program is free software; you can redistribute it and/or modify | |
| 7 | + * it under the terms of the GNU General Public License as published by | |
| 8 | + * the Free Software Foundation; version 2 of the License. | |
| 9 | + * | |
| 10 | + * This program is distributed in the hope that it will be useful, | |
| 11 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| 12 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| 13 | + * GNU General Public License for more details. | |
| 14 | + * | |
| 15 | + * You should have received a copy of the GNU General Public License | |
| 16 | + * along with this program; if not, write to the Free Software | |
| 17 | + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
| 18 | + * 02110-1301 USA. | |
| 19 | + * | |
| 20 | + */ | |
| 21 | + | |
| 22 | +#include <linux/module.h> | |
| 23 | +#include <linux/skbuff.h> | |
| 24 | +#include <linux/netfilter/x_tables.h> | |
| 25 | +#include <linux/leds.h> | |
| 26 | +#include <linux/mutex.h> | |
| 27 | + | |
| 28 | +#include <linux/netfilter/xt_LED.h> | |
| 29 | + | |
| 30 | +MODULE_LICENSE("GPL"); | |
| 31 | +MODULE_AUTHOR("Adam Nielsen <a.nielsen@shikadi.net>"); | |
| 32 | +MODULE_DESCRIPTION("Xtables: trigger LED devices on packet match"); | |
| 33 | + | |
| 34 | +/* | |
| 35 | + * This is declared in here (the kernel module) only, to avoid having these | |
| 36 | + * dependencies in userspace code. This is what xt_led_info.internal_data | |
| 37 | + * points to. | |
| 38 | + */ | |
| 39 | +struct xt_led_info_internal { | |
| 40 | + struct led_trigger netfilter_led_trigger; | |
| 41 | + struct timer_list timer; | |
| 42 | +}; | |
| 43 | + | |
| 44 | +static unsigned int | |
| 45 | +led_tg(struct sk_buff *skb, const struct xt_target_param *par) | |
| 46 | +{ | |
| 47 | + const struct xt_led_info *ledinfo = par->targinfo; | |
| 48 | + struct xt_led_info_internal *ledinternal = ledinfo->internal_data; | |
| 49 | + | |
| 50 | + /* | |
| 51 | + * If "always blink" is enabled, and there's still some time until the | |
| 52 | + * LED will switch off, briefly switch it off now. | |
| 53 | + */ | |
| 54 | + if ((ledinfo->delay > 0) && ledinfo->always_blink && | |
| 55 | + timer_pending(&ledinternal->timer)) | |
| 56 | + led_trigger_event(&ledinternal->netfilter_led_trigger,LED_OFF); | |
| 57 | + | |
| 58 | + led_trigger_event(&ledinternal->netfilter_led_trigger, LED_FULL); | |
| 59 | + | |
| 60 | + /* If there's a positive delay, start/update the timer */ | |
| 61 | + if (ledinfo->delay > 0) { | |
| 62 | + mod_timer(&ledinternal->timer, | |
| 63 | + jiffies + msecs_to_jiffies(ledinfo->delay)); | |
| 64 | + | |
| 65 | + /* Otherwise if there was no delay given, blink as fast as possible */ | |
| 66 | + } else if (ledinfo->delay == 0) { | |
| 67 | + led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); | |
| 68 | + } | |
| 69 | + | |
| 70 | + /* else the delay is negative, which means switch on and stay on */ | |
| 71 | + | |
| 72 | + return XT_CONTINUE; | |
| 73 | +} | |
| 74 | + | |
| 75 | +static void led_timeout_callback(unsigned long data) | |
| 76 | +{ | |
| 77 | + struct xt_led_info *ledinfo = (struct xt_led_info *)data; | |
| 78 | + struct xt_led_info_internal *ledinternal = ledinfo->internal_data; | |
| 79 | + | |
| 80 | + led_trigger_event(&ledinternal->netfilter_led_trigger, LED_OFF); | |
| 81 | +} | |
| 82 | + | |
| 83 | +static bool led_tg_check(const struct xt_tgchk_param *par) | |
| 84 | +{ | |
| 85 | + struct xt_led_info *ledinfo = par->targinfo; | |
| 86 | + struct xt_led_info_internal *ledinternal; | |
| 87 | + int err; | |
| 88 | + | |
| 89 | + if (ledinfo->id[0] == '\0') { | |
| 90 | + printk(KERN_ERR KBUILD_MODNAME ": No 'id' parameter given.\n"); | |
| 91 | + return false; | |
| 92 | + } | |
| 93 | + | |
| 94 | + ledinternal = kzalloc(sizeof(struct xt_led_info_internal), GFP_KERNEL); | |
| 95 | + if (!ledinternal) { | |
| 96 | + printk(KERN_CRIT KBUILD_MODNAME ": out of memory\n"); | |
| 97 | + return false; | |
| 98 | + } | |
| 99 | + | |
| 100 | + ledinternal->netfilter_led_trigger.name = ledinfo->id; | |
| 101 | + | |
| 102 | + err = led_trigger_register(&ledinternal->netfilter_led_trigger); | |
| 103 | + if (err) { | |
| 104 | + printk(KERN_CRIT KBUILD_MODNAME | |
| 105 | + ": led_trigger_register() failed\n"); | |
| 106 | + if (err == -EEXIST) | |
| 107 | + printk(KERN_ERR KBUILD_MODNAME | |
| 108 | + ": Trigger name is already in use.\n"); | |
| 109 | + goto exit_alloc; | |
| 110 | + } | |
| 111 | + | |
| 112 | + /* See if we need to set up a timer */ | |
| 113 | + if (ledinfo->delay > 0) | |
| 114 | + setup_timer(&ledinternal->timer, led_timeout_callback, | |
| 115 | + (unsigned long)ledinfo); | |
| 116 | + | |
| 117 | + ledinfo->internal_data = ledinternal; | |
| 118 | + | |
| 119 | + return true; | |
| 120 | + | |
| 121 | +exit_alloc: | |
| 122 | + kfree(ledinternal); | |
| 123 | + | |
| 124 | + return false; | |
| 125 | +} | |
| 126 | + | |
| 127 | +static void led_tg_destroy(const struct xt_tgdtor_param *par) | |
| 128 | +{ | |
| 129 | + const struct xt_led_info *ledinfo = par->targinfo; | |
| 130 | + struct xt_led_info_internal *ledinternal = ledinfo->internal_data; | |
| 131 | + | |
| 132 | + if (ledinfo->delay > 0) | |
| 133 | + del_timer_sync(&ledinternal->timer); | |
| 134 | + | |
| 135 | + led_trigger_unregister(&ledinternal->netfilter_led_trigger); | |
| 136 | + kfree(ledinternal); | |
| 137 | +} | |
| 138 | + | |
| 139 | +static struct xt_target led_tg_reg __read_mostly = { | |
| 140 | + .name = "LED", | |
| 141 | + .revision = 0, | |
| 142 | + .family = NFPROTO_UNSPEC, | |
| 143 | + .target = led_tg, | |
| 144 | + .targetsize = XT_ALIGN(sizeof(struct xt_led_info)), | |
| 145 | + .checkentry = led_tg_check, | |
| 146 | + .destroy = led_tg_destroy, | |
| 147 | + .me = THIS_MODULE, | |
| 148 | +}; | |
| 149 | + | |
| 150 | +static int __init led_tg_init(void) | |
| 151 | +{ | |
| 152 | + return xt_register_target(&led_tg_reg); | |
| 153 | +} | |
| 154 | + | |
| 155 | +static void __exit led_tg_exit(void) | |
| 156 | +{ | |
| 157 | + xt_unregister_target(&led_tg_reg); | |
| 158 | +} | |
| 159 | + | |
| 160 | +module_init(led_tg_init); | |
| 161 | +module_exit(led_tg_exit); | |
| @@ -0,0 +1,164 @@ | ||
| 1 | +/* | |
| 2 | + * (C) 2008-2009 Pablo Neira Ayuso <pablo@netfilter.org> | |
| 3 | + * | |
| 4 | + * This program is free software; you can redistribute it and/or modify | |
| 5 | + * it under the terms of the GNU General Public License version 2 as | |
| 6 | + * published by the Free Software Foundation. | |
| 7 | + */ | |
| 8 | +#include <linux/module.h> | |
| 9 | +#include <linux/skbuff.h> | |
| 10 | +#include <linux/jhash.h> | |
| 11 | +#include <linux/ip.h> | |
| 12 | +#include <net/ipv6.h> | |
| 13 | + | |
| 14 | +#include <linux/netfilter/x_tables.h> | |
| 15 | +#include <net/netfilter/nf_conntrack.h> | |
| 16 | +#include <linux/netfilter/xt_cluster.h> | |
| 17 | + | |
| 18 | +static inline u_int32_t nf_ct_orig_ipv4_src(const struct nf_conn *ct) | |
| 19 | +{ | |
| 20 | + return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip; | |
| 21 | +} | |
| 22 | + | |
| 23 | +static inline const void *nf_ct_orig_ipv6_src(const struct nf_conn *ct) | |
| 24 | +{ | |
| 25 | + return ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6; | |
| 26 | +} | |
| 27 | + | |
| 28 | +static inline u_int32_t | |
| 29 | +xt_cluster_hash_ipv4(u_int32_t ip, const struct xt_cluster_match_info *info) | |
| 30 | +{ | |
| 31 | + return jhash_1word(ip, info->hash_seed); | |
| 32 | +} | |
| 33 | + | |
| 34 | +static inline u_int32_t | |
| 35 | +xt_cluster_hash_ipv6(const void *ip, const struct xt_cluster_match_info *info) | |
| 36 | +{ | |
| 37 | + return jhash2(ip, NF_CT_TUPLE_L3SIZE / sizeof(__u32), info->hash_seed); | |
| 38 | +} | |
| 39 | + | |
| 40 | +static inline u_int32_t | |
| 41 | +xt_cluster_hash(const struct nf_conn *ct, | |
| 42 | + const struct xt_cluster_match_info *info) | |
| 43 | +{ | |
| 44 | + u_int32_t hash = 0; | |
| 45 | + | |
| 46 | + switch(nf_ct_l3num(ct)) { | |
| 47 | + case AF_INET: | |
| 48 | + hash = xt_cluster_hash_ipv4(nf_ct_orig_ipv4_src(ct), info); | |
| 49 | + break; | |
| 50 | + case AF_INET6: | |
| 51 | + hash = xt_cluster_hash_ipv6(nf_ct_orig_ipv6_src(ct), info); | |
| 52 | + break; | |
| 53 | + default: | |
| 54 | + WARN_ON(1); | |
| 55 | + break; | |
| 56 | + } | |
| 57 | + return (((u64)hash * info->total_nodes) >> 32); | |
| 58 | +} | |
| 59 | + | |
| 60 | +static inline bool | |
| 61 | +xt_cluster_is_multicast_addr(const struct sk_buff *skb, u_int8_t family) | |
| 62 | +{ | |
| 63 | + bool is_multicast = false; | |
| 64 | + | |
| 65 | + switch(family) { | |
| 66 | + case NFPROTO_IPV4: | |
| 67 | + is_multicast = ipv4_is_multicast(ip_hdr(skb)->daddr); | |
| 68 | + break; | |
| 69 | + case NFPROTO_IPV6: | |
| 70 | + is_multicast = ipv6_addr_type(&ipv6_hdr(skb)->daddr) & | |
| 71 | + IPV6_ADDR_MULTICAST; | |
| 72 | + break; | |
| 73 | + default: | |
| 74 | + WARN_ON(1); | |
| 75 | + break; | |
| 76 | + } | |
| 77 | + return is_multicast; | |
| 78 | +} | |
| 79 | + | |
| 80 | +static bool | |
| 81 | +xt_cluster_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |
| 82 | +{ | |
| 83 | + struct sk_buff *pskb = (struct sk_buff *)skb; | |
| 84 | + const struct xt_cluster_match_info *info = par->matchinfo; | |
| 85 | + const struct nf_conn *ct; | |
| 86 | + enum ip_conntrack_info ctinfo; | |
| 87 | + unsigned long hash; | |
| 88 | + | |
| 89 | + /* This match assumes that all nodes see the same packets. This can be | |
| 90 | + * achieved if the switch that connects the cluster nodes support some | |
| 91 | + * sort of 'port mirroring'. However, if your switch does not support | |
| 92 | + * this, your cluster nodes can reply ARP request using a multicast MAC | |
| 93 | + * address. Thus, your switch will flood the same packets to the | |
| 94 | + * cluster nodes with the same multicast MAC address. Using a multicast | |
| 95 | + * link address is a RFC 1812 (section 3.3.2) violation, but this works | |
| 96 | + * fine in practise. | |
| 97 | + * | |
| 98 | + * Unfortunately, if you use the multicast MAC address, the link layer | |
| 99 | + * sets skbuff's pkt_type to PACKET_MULTICAST, which is not accepted | |
| 100 | + * by TCP and others for packets coming to this node. For that reason, | |
| 101 | + * this match mangles skbuff's pkt_type if it detects a packet | |
| 102 | + * addressed to a unicast address but using PACKET_MULTICAST. Yes, I | |
| 103 | + * know, matches should not alter packets, but we are doing this here | |
| 104 | + * because we would need to add a PKTTYPE target for this sole purpose. | |
| 105 | + */ | |
| 106 | + if (!xt_cluster_is_multicast_addr(skb, par->family) && | |
| 107 | + skb->pkt_type == PACKET_MULTICAST) { | |
| 108 | + pskb->pkt_type = PACKET_HOST; | |
| 109 | + } | |
| 110 | + | |
| 111 | + ct = nf_ct_get(skb, &ctinfo); | |
| 112 | + if (ct == NULL) | |
| 113 | + return false; | |
| 114 | + | |
| 115 | + if (ct == &nf_conntrack_untracked) | |
| 116 | + return false; | |
| 117 | + | |
| 118 | + if (ct->master) | |
| 119 | + hash = xt_cluster_hash(ct->master, info); | |
| 120 | + else | |
| 121 | + hash = xt_cluster_hash(ct, info); | |
| 122 | + | |
| 123 | + return !!((1 << hash) & info->node_mask) ^ | |
| 124 | + !!(info->flags & XT_CLUSTER_F_INV); | |
| 125 | +} | |
| 126 | + | |
| 127 | +static bool xt_cluster_mt_checkentry(const struct xt_mtchk_param *par) | |
| 128 | +{ | |
| 129 | + struct xt_cluster_match_info *info = par->matchinfo; | |
| 130 | + | |
| 131 | + if (info->node_mask >= (1 << info->total_nodes)) { | |
| 132 | + printk(KERN_ERR "xt_cluster: this node mask cannot be " | |
| 133 | + "higher than the total number of nodes\n"); | |
| 134 | + return false; | |
| 135 | + } | |
| 136 | + return true; | |
| 137 | +} | |
| 138 | + | |
| 139 | +static struct xt_match xt_cluster_match __read_mostly = { | |
| 140 | + .name = "cluster", | |
| 141 | + .family = NFPROTO_UNSPEC, | |
| 142 | + .match = xt_cluster_mt, | |
| 143 | + .checkentry = xt_cluster_mt_checkentry, | |
| 144 | + .matchsize = sizeof(struct xt_cluster_match_info), | |
| 145 | + .me = THIS_MODULE, | |
| 146 | +}; | |
| 147 | + | |
| 148 | +static int __init xt_cluster_mt_init(void) | |
| 149 | +{ | |
| 150 | + return xt_register_match(&xt_cluster_match); | |
| 151 | +} | |
| 152 | + | |
| 153 | +static void __exit xt_cluster_mt_fini(void) | |
| 154 | +{ | |
| 155 | + xt_unregister_match(&xt_cluster_match); | |
| 156 | +} | |
| 157 | + | |
| 158 | +MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>"); | |
| 159 | +MODULE_LICENSE("GPL"); | |
| 160 | +MODULE_DESCRIPTION("Xtables: hash-based cluster match"); | |
| 161 | +MODULE_ALIAS("ipt_cluster"); | |
| 162 | +MODULE_ALIAS("ip6t_cluster"); | |
| 163 | +module_init(xt_cluster_mt_init); | |
| 164 | +module_exit(xt_cluster_mt_fini); | |
| @@ -149,7 +149,7 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht, · 148 unmodified lines | ||
| 149 | 149 | /* initialize hash with random val at the time we allocate |
| 150 | 150 | * the first hashtable entry */ |
| 151 | 151 | if (!ht->rnd_initialized) { |
| 152 | − get_random_bytes(&ht->rnd, 4); | |
| 152 | + get_random_bytes(&ht->rnd, sizeof(ht->rnd)); | |
| 153 | 153 | ht->rnd_initialized = 1; |
| 154 | 154 | } |
| 155 | 155 | |
| @@ -565,8 +565,7 @@ hashlimit_init_dst(const struct xt_hashlimit_htable *hinfo, · 409 unmodified lines | ||
| 565 | 565 | static bool |
| 566 | 566 | hashlimit_mt_v0(const struct sk_buff *skb, const struct xt_match_param *par) |
| 567 | 567 | { |
| 568 | − const struct xt_hashlimit_info *r = | |
| 569 | − ((const struct xt_hashlimit_info *)par->matchinfo)->u.master; | |
| 568 | + const struct xt_hashlimit_info *r = par->matchinfo; | |
| 570 | 569 | struct xt_hashlimit_htable *hinfo = r->hinfo; |
| 571 | 570 | unsigned long now = jiffies; |
| 572 | 571 | struct dsthash_ent *dh; |
| @@ -702,8 +701,6 @@ static bool hashlimit_mt_check_v0(const struct xt_mtchk_param *par) · 129 unmodified lines | ||
| 702 | 701 | } |
| 703 | 702 | mutex_unlock(&hlimit_mutex); |
| 704 | 703 | |
| 705 | − /* Ugly hack: For SMP, we only want to use one set */ | |
| 706 | − r->u.master = r; | |
| 707 | 704 | return true; |
| 708 | 705 | } |
| 709 | 706 | |
| @@ -0,0 +1,108 @@ | ||
| 1 | +/* | |
| 2 | + * IP tables module for matching the value of the TTL | |
| 3 | + * (C) 2000,2001 by Harald Welte <laforge@netfilter.org> | |
| 4 | + * | |
| 5 | + * Hop Limit matching module | |
| 6 | + * (C) 2001-2002 Maciej Soltysiak <solt@dns.toxicfilms.tv> | |
| 7 | + * | |
| 8 | + * This program is free software; you can redistribute it and/or modify | |
| 9 | + * it under the terms of the GNU General Public License version 2 as | |
| 10 | + * published by the Free Software Foundation. | |
| 11 | + */ | |
| 12 | + | |
| 13 | +#include <linux/ip.h> | |
| 14 | +#include <linux/ipv6.h> | |
| 15 | +#include <linux/module.h> | |
| 16 | +#include <linux/skbuff.h> | |
| 17 | + | |
| 18 | +#include <linux/netfilter/x_tables.h> | |
| 19 | +#include <linux/netfilter_ipv4/ipt_ttl.h> | |
| 20 | +#include <linux/netfilter_ipv6/ip6t_hl.h> | |
| 21 | + | |
| 22 | +MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>"); | |
| 23 | +MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match"); | |
| 24 | +MODULE_LICENSE("GPL"); | |
| 25 | +MODULE_ALIAS("ipt_ttl"); | |
| 26 | +MODULE_ALIAS("ip6t_hl"); | |
| 27 | + | |
| 28 | +static bool ttl_mt(const struct sk_buff *skb, const struct xt_match_param *par) | |
| 29 | +{ | |
| 30 | + const struct ipt_ttl_info *info = par->matchinfo; | |
| 31 | + const u8 ttl = ip_hdr(skb)->ttl; | |
| 32 | + | |
| 33 | + switch (info->mode) { | |
| 34 | + case IPT_TTL_EQ: | |
| 35 | + return ttl == info->ttl; | |
| 36 | + case IPT_TTL_NE: | |
| 37 | + return ttl != info->ttl; | |
| 38 | + case IPT_TTL_LT: | |
| 39 | + return ttl < info->ttl; | |
| 40 | + case IPT_TTL_GT: | |
| 41 | + return ttl > info->ttl; | |
| 42 | + default: | |
| 43 | + printk(KERN_WARNING "ipt_ttl: unknown mode %d\n", | |
| 44 | + info->mode); | |
| 45 | + return false; | |
| 46 | + } | |
| 47 | + | |
| 48 | + return false; | |
| 49 | +} | |
| 50 | + | |
| 51 | +static bool hl_mt6(const struct sk_buff *skb, const struct xt_match_param *par) | |
| 52 | +{ | |
| 53 | + const struct ip6t_hl_info *info = par->matchinfo; | |
| 54 | + const struct ipv6hdr *ip6h = ipv6_hdr(skb); | |
| 55 | + | |
| 56 | + switch (info->mode) { | |
| 57 | + case IP6T_HL_EQ: | |
| 58 | + return ip6h->hop_limit == info->hop_limit; | |
| 59 | + break; | |
| 60 | + case IP6T_HL_NE: | |
| 61 | + return ip6h->hop_limit != info->hop_limit; | |
| 62 | + break; | |
| 63 | + case IP6T_HL_LT: | |
| 64 | + return ip6h->hop_limit < info->hop_limit; | |
| 65 | + break; | |
| 66 | + case IP6T_HL_GT: | |
| 67 | + return ip6h->hop_limit > info->hop_limit; | |
| 68 | + break; | |
| 69 | + default: | |
| 70 | + printk(KERN_WARNING "ip6t_hl: unknown mode %d\n", | |
| 71 | + info->mode); | |
| 72 | + return false; | |
| 73 | + } | |
| 74 | + | |
| 75 | + return false; | |
| 76 | +} | |
| 77 | + | |
| 78 | +static struct xt_match hl_mt_reg[] __read_mostly = { | |
| 79 | + { | |
| 80 | + .name = "ttl", | |
| 81 | + .revision = 0, | |
| 82 | + .family = NFPROTO_IPV4, | |
| 83 | + .match = ttl_mt, | |
| 84 | + .matchsize = sizeof(struct ipt_ttl_info), | |
| 85 | + .me = THIS_MODULE, | |
| 86 | + }, | |
| 87 | + { | |
| 88 | + .name = "hl", | |
| 89 | + .revision = 0, | |
| 90 | + .family = NFPROTO_IPV6, | |
| 91 | + .match = hl_mt6, | |
| 92 | + .matchsize = sizeof(struct ip6t_hl_info), | |
| 93 | + .me = THIS_MODULE, | |
| 94 | + }, | |
| 95 | +}; | |
| 96 | + | |
| 97 | +static int __init hl_mt_init(void) | |
| 98 | +{ | |
| 99 | + return xt_register_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); | |
| 100 | +} | |
| 101 | + | |
| 102 | +static void __exit hl_mt_exit(void) | |
| 103 | +{ | |
| 104 | + xt_unregister_matches(hl_mt_reg, ARRAY_SIZE(hl_mt_reg)); | |
| 105 | +} | |
| 106 | + | |
| 107 | +module_init(hl_mt_init); | |
| 108 | +module_exit(hl_mt_exit); | |
| @@ -14,6 +14,11 @@ · 13 unmodified lines | ||
| 14 | 14 | #include <linux/netfilter/x_tables.h> |
| 15 | 15 | #include <linux/netfilter/xt_limit.h> |
| 16 | 16 | |
| 17 | +struct xt_limit_priv { | |
| 18 | + unsigned long prev; | |
| 19 | + uint32_t credit; | |
| 20 | +}; | |
| 21 | + | |
| 17 | 22 | MODULE_LICENSE("GPL"); |
| 18 | 23 | MODULE_AUTHOR("Herve Eychenne <rv@wallfire.org>"); |
| 19 | 24 | MODULE_DESCRIPTION("Xtables: rate-limit match"); |
| @@ -60,18 +65,18 @@ static DEFINE_SPINLOCK(limit_lock); · 40 unmodified lines | ||
| 60 | 65 | static bool |
| 61 | 66 | limit_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
| 62 | 67 | { |
| 63 | − struct xt_rateinfo *r = | |
| 64 | − ((const struct xt_rateinfo *)par->matchinfo)->master; | |
| 68 | + const struct xt_rateinfo *r = par->matchinfo; | |
| 69 | + struct xt_limit_priv *priv = r->master; | |
| 65 | 70 | unsigned long now = jiffies; |
| 66 | 71 | |
| 67 | 72 | spin_lock_bh(&limit_lock); |
| 68 | − r->credit += (now - xchg(&r->prev, now)) * CREDITS_PER_JIFFY; | |
| 69 | − if (r->credit > r->credit_cap) | |
| 70 | − r->credit = r->credit_cap; | |
| 73 | + priv->credit += (now - xchg(&priv->prev, now)) * CREDITS_PER_JIFFY; | |
| 74 | + if (priv->credit > r->credit_cap) | |
| 75 | + priv->credit = r->credit_cap; | |
| 71 | 76 | |
| 72 | − if (r->credit >= r->cost) { | |
| 77 | + if (priv->credit >= r->cost) { | |
| 73 | 78 | /* We're not limited. */ |
| 74 | − r->credit -= r->cost; | |
| 79 | + priv->credit -= r->cost; | |
| 75 | 80 | spin_unlock_bh(&limit_lock); |
| 76 | 81 | return true; |
| 77 | 82 | } |
| @@ -95,6 +100,7 @@ user2credits(u_int32_t user) · 17 unmodified lines | ||
| 95 | 100 | static bool limit_mt_check(const struct xt_mtchk_param *par) |
| 96 | 101 | { |
| 97 | 102 | struct xt_rateinfo *r = par->matchinfo; |
| 103 | + struct xt_limit_priv *priv; | |
| 98 | 104 | |
| 99 | 105 | /* Check for overflow. */ |
| 100 | 106 | if (r->burst == 0 |
| @@ -104,19 +110,30 @@ static bool limit_mt_check(const struct xt_mtchk_param *par) · 3 unmodified lines | ||
| 104 | 110 | return false; |
| 105 | 111 | } |
| 106 | 112 | |
| 107 | − /* For SMP, we only want to use one set of counters. */ | |
| 108 | − r->master = r; | |
| 113 | + priv = kmalloc(sizeof(*priv), GFP_KERNEL); | |
| 114 | + if (priv == NULL) | |
| 115 | + return -ENOMEM; | |
| 116 | + | |
| 117 | + /* For SMP, we only want to use one set of state. */ | |
| 118 | + r->master = priv; | |
| 109 | 119 | if (r->cost == 0) { |
| 110 | 120 | /* User avg in seconds * XT_LIMIT_SCALE: convert to jiffies * |
| 111 | 121 | 128. */ |
| 112 | − r->prev = jiffies; | |
| 113 | − r->credit = user2credits(r->avg * r->burst); /* Credits full. */ | |
| 122 | + priv->prev = jiffies; | |
| 123 | + priv->credit = user2credits(r->avg * r->burst); /* Credits full. */ | |
| 114 | 124 | r->credit_cap = user2credits(r->avg * r->burst); /* Credits full. */ |
| 115 | 125 | r->cost = user2credits(r->avg); |
| 116 | 126 | } |
| 117 | 127 | return true; |
| 118 | 128 | } |
| 119 | 129 | |
| 130 | +static void limit_mt_destroy(const struct xt_mtdtor_param *par) | |
| 131 | +{ | |
| 132 | + const struct xt_rateinfo *info = par->matchinfo; | |
| 133 | + | |
| 134 | + kfree(info->master); | |
| 135 | +} | |
| 136 | + | |
| 120 | 137 | #ifdef CONFIG_COMPAT |
| 121 | 138 | struct compat_xt_rateinfo { |
| 122 | 139 | u_int32_t avg; |
| @@ -167,6 +184,7 @@ static struct xt_match limit_mt_reg __read_mostly = { · 44 unmodified lines | ||
| 167 | 184 | .family = NFPROTO_UNSPEC, |
| 168 | 185 | .match = limit_mt, |
| 169 | 186 | .checkentry = limit_mt_check, |
| 187 | + .destroy = limit_mt_destroy, | |
| 170 | 188 | .matchsize = sizeof(struct xt_rateinfo), |
| 171 | 189 | #ifdef CONFIG_COMPAT |
| 172 | 190 | .compatsize = sizeof(struct compat_xt_rateinfo), |
| @@ -20,13 +20,30 @@ MODULE_DESCRIPTION("Xtables: Bridge physical device match"); · 19 unmodified lines | ||
| 20 | 20 | MODULE_ALIAS("ipt_physdev"); |
| 21 | 21 | MODULE_ALIAS("ip6t_physdev"); |
| 22 | 22 | |
| 23 | +static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask) | |
| 24 | +{ | |
| 25 | + const unsigned long *a = (const unsigned long *)_a; | |
| 26 | + const unsigned long *b = (const unsigned long *)_b; | |
| 27 | + const unsigned long *mask = (const unsigned long *)_mask; | |
| 28 | + unsigned long ret; | |
| 29 | + | |
| 30 | + ret = (a[0] ^ b[0]) & mask[0]; | |
| 31 | + if (IFNAMSIZ > sizeof(unsigned long)) | |
| 32 | + ret |= (a[1] ^ b[1]) & mask[1]; | |
| 33 | + if (IFNAMSIZ > 2 * sizeof(unsigned long)) | |
| 34 | + ret |= (a[2] ^ b[2]) & mask[2]; | |
| 35 | + if (IFNAMSIZ > 3 * sizeof(unsigned long)) | |
| 36 | + ret |= (a[3] ^ b[3]) & mask[3]; | |
| 37 | + BUILD_BUG_ON(IFNAMSIZ > 4 * sizeof(unsigned long)); | |
| 38 | + return ret; | |
| 39 | +} | |
| 40 | + | |
| 23 | 41 | static bool |
| 24 | 42 | physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
| 25 | 43 | { |
| 26 | − int i; | |
| 27 | − static const char nulldevname[IFNAMSIZ]; | |
| 44 | + static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long)))); | |
| 28 | 45 | const struct xt_physdev_info *info = par->matchinfo; |
| 29 | − bool ret; | |
| 46 | + unsigned long ret; | |
| 30 | 47 | const char *indev, *outdev; |
| 31 | 48 | const struct nf_bridge_info *nf_bridge; |
| 32 | 49 | |
| @@ -68,11 +85,7 @@ physdev_mt(const struct sk_buff *skb, const struct xt_match_param *par) · 35 unmodified lines | ||
| 68 | 85 | if (!(info->bitmask & XT_PHYSDEV_OP_IN)) |
| 69 | 86 | goto match_outdev; |
| 70 | 87 | indev = nf_bridge->physindev ? nf_bridge->physindev->name : nulldevname; |
| 71 | − for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) { | |
| 72 | − ret |= (((const unsigned int *)indev)[i] | |
| 73 | − ^ ((const unsigned int *)info->physindev)[i]) | |
| 74 | − & ((const unsigned int *)info->in_mask)[i]; | |
| 75 | − } | |
| 88 | + ret = ifname_compare(indev, info->physindev, info->in_mask); | |
| 76 | 89 | |
| 77 | 90 | if (!ret ^ !(info->invert & XT_PHYSDEV_OP_IN)) |
| 78 | 91 | return false; |
| @@ -82,13 +95,9 @@ match_outdev: · 3 unmodified lines | ||
| 82 | 95 | return true; |
| 83 | 96 | outdev = nf_bridge->physoutdev ? |
| 84 | 97 | nf_bridge->physoutdev->name : nulldevname; |
| 85 | − for (i = 0, ret = false; i < IFNAMSIZ/sizeof(unsigned int); i++) { | |
| 86 | − ret |= (((const unsigned int *)outdev)[i] | |
| 87 | − ^ ((const unsigned int *)info->physoutdev)[i]) | |
| 88 | − & ((const unsigned int *)info->out_mask)[i]; | |
| 89 | − } | |
| 98 | + ret = ifname_compare(outdev, info->physoutdev, info->out_mask); | |
| 90 | 99 | |
| 91 | − return ret ^ !(info->invert & XT_PHYSDEV_OP_OUT); | |
| 100 | + return (!!ret ^ !(info->invert & XT_PHYSDEV_OP_OUT)); | |
| 92 | 101 | } |
| 93 | 102 | |
| 94 | 103 | static bool physdev_mt_check(const struct xt_mtchk_param *par) |
| @@ -9,6 +9,10 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/netfilter/x_tables.h> |
| 10 | 10 | #include <linux/netfilter/xt_quota.h> |
| 11 | 11 | |
| 12 | +struct xt_quota_priv { | |
| 13 | + uint64_t quota; | |
| 14 | +}; | |
| 15 | + | |
| 12 | 16 | MODULE_LICENSE("GPL"); |
| 13 | 17 | MODULE_AUTHOR("Sam Johnston <samj@samj.net>"); |
| 14 | 18 | MODULE_DESCRIPTION("Xtables: countdown quota match"); |
| @@ -20,18 +24,20 @@ static DEFINE_SPINLOCK(quota_lock); · 5 unmodified lines | ||
| 20 | 24 | static bool |
| 21 | 25 | quota_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
| 22 | 26 | { |
| 23 | − struct xt_quota_info *q = | |
| 24 | − ((const struct xt_quota_info *)par->matchinfo)->master; | |
| 27 | + struct xt_quota_info *q = (void *)par->matchinfo; | |
| 28 | + struct xt_quota_priv *priv = q->master; | |
| 25 | 29 | bool ret = q->flags & XT_QUOTA_INVERT; |
| 26 | 30 | |
| 27 | 31 | spin_lock_bh("a_lock); |
| 28 | − if (q->quota >= skb->len) { | |
| 29 | − q->quota -= skb->len; | |
| 32 | + if (priv->quota >= skb->len) { | |
| 33 | + priv->quota -= skb->len; | |
| 30 | 34 | ret = !ret; |
| 31 | 35 | } else { |
| 32 | 36 | /* we do not allow even small packets from now on */ |
| 33 | − q->quota = 0; | |
| 37 | + priv->quota = 0; | |
| 34 | 38 | } |
| 39 | + /* Copy quota back to matchinfo so that iptables can display it */ | |
| 40 | + q->quota = priv->quota; | |
| 35 | 41 | spin_unlock_bh("a_lock); |
| 36 | 42 | |
| 37 | 43 | return ret; |
| @@ -43,17 +49,28 @@ static bool quota_mt_check(const struct xt_mtchk_param *par) · 5 unmodified lines | ||
| 43 | 49 | |
| 44 | 50 | if (q->flags & ~XT_QUOTA_MASK) |
| 45 | 51 | return false; |
| 46 | − /* For SMP, we only want to use one set of counters. */ | |
| 47 | − q->master = q; | |
| 52 | + | |
| 53 | + q->master = kmalloc(sizeof(*q->master), GFP_KERNEL); | |
| 54 | + if (q->master == NULL) | |
| 55 | + return -ENOMEM; | |
| 56 | + | |
| 48 | 57 | return true; |
| 49 | 58 | } |
| 50 | 59 | |
| 60 | +static void quota_mt_destroy(const struct xt_mtdtor_param *par) | |
| 61 | +{ | |
| 62 | + const struct xt_quota_info *q = par->matchinfo; | |
| 63 | + | |
| 64 | + kfree(q->master); | |
| 65 | +} | |
| 66 | + | |
| 51 | 67 | static struct xt_match quota_mt_reg __read_mostly = { |
| 52 | 68 | .name = "quota", |
| 53 | 69 | .revision = 0, |
| 54 | 70 | .family = NFPROTO_UNSPEC, |
| 55 | 71 | .match = quota_mt, |
| 56 | 72 | .checkentry = quota_mt_check, |
| 73 | + .destroy = quota_mt_destroy, | |
| 57 | 74 | .matchsize = sizeof(struct xt_quota_info), |
| 58 | 75 | .me = THIS_MODULE, |
| 59 | 76 | }; |
| @@ -16,6 +16,10 @@ · 15 unmodified lines | ||
| 16 | 16 | #include <linux/netfilter/xt_statistic.h> |
| 17 | 17 | #include <linux/netfilter/x_tables.h> |
| 18 | 18 | |
| 19 | +struct xt_statistic_priv { | |
| 20 | + uint32_t count; | |
| 21 | +}; | |
| 22 | + | |
| 19 | 23 | MODULE_LICENSE("GPL"); |
| 20 | 24 | MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>"); |
| 21 | 25 | MODULE_DESCRIPTION("Xtables: statistics-based matching (\"Nth\", random)"); |
| @@ -27,7 +31,7 @@ static DEFINE_SPINLOCK(nth_lock); · 5 unmodified lines | ||
| 27 | 31 | static bool |
| 28 | 32 | statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par) |
| 29 | 33 | { |
| 30 | − struct xt_statistic_info *info = (void *)par->matchinfo; | |
| 34 | + const struct xt_statistic_info *info = par->matchinfo; | |
| 31 | 35 | bool ret = info->flags & XT_STATISTIC_INVERT; |
| 32 | 36 | |
| 33 | 37 | switch (info->mode) { |
| @@ -36,10 +40,9 @@ statistic_mt(const struct sk_buff *skb, const struct xt_match_param *par) · 2 unmodified lines | ||
| 36 | 40 | ret = !ret; |
| 37 | 41 | break; |
| 38 | 42 | case XT_STATISTIC_MODE_NTH: |
| 39 | − info = info->master; | |
| 40 | 43 | spin_lock_bh(&nth_lock); |
| 41 | − if (info->u.nth.count++ == info->u.nth.every) { | |
| 42 | − info->u.nth.count = 0; | |
| 44 | + if (info->master->count++ == info->u.nth.every) { | |
| 45 | + info->master->count = 0; | |
| 43 | 46 | ret = !ret; |
| 44 | 47 | } |
| 45 | 48 | spin_unlock_bh(&nth_lock); |
| @@ -56,16 +59,31 @@ static bool statistic_mt_check(const struct xt_mtchk_param *par) · 10 unmodified lines | ||
| 56 | 59 | if (info->mode > XT_STATISTIC_MODE_MAX || |
| 57 | 60 | info->flags & ~XT_STATISTIC_MASK) |
| 58 | 61 | return false; |
| 59 | − info->master = info; | |
| 62 | + | |
| 63 | + info->master = kzalloc(sizeof(*info->master), GFP_KERNEL); | |
| 64 | + if (info->master == NULL) { | |
| 65 | + printk(KERN_ERR KBUILD_MODNAME ": Out of memory\n"); | |
| 66 | + return false; | |
| 67 | + } | |
| 68 | + info->master->count = info->u.nth.count; | |
| 69 | + | |
| 60 | 70 | return true; |
| 61 | 71 | } |
| 62 | 72 | |
| 73 | +static void statistic_mt_destroy(const struct xt_mtdtor_param *par) | |
| 74 | +{ | |
| 75 | + const struct xt_statistic_info *info = par->matchinfo; | |
| 76 | + | |
| 77 | + kfree(info->master); | |
| 78 | +} | |
| 79 | + | |
| 63 | 80 | static struct xt_match xt_statistic_mt_reg __read_mostly = { |
| 64 | 81 | .name = "statistic", |
| 65 | 82 | .revision = 0, |
| 66 | 83 | .family = NFPROTO_UNSPEC, |
| 67 | 84 | .match = statistic_mt, |
| 68 | 85 | .checkentry = statistic_mt_check, |
| 86 | + .destroy = statistic_mt_destroy, | |
| 69 | 87 | .matchsize = sizeof(struct xt_statistic_info), |
| 70 | 88 | .me = THIS_MODULE, |
| 71 | 89 | }; |
| @@ -1117,6 +1117,7 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code) · 1116 unmodified lines | ||
| 1117 | 1117 | |
| 1118 | 1118 | read_unlock(&nl_table_lock); |
| 1119 | 1119 | } |
| 1120 | +EXPORT_SYMBOL(netlink_set_err); | |
| 1120 | 1121 | |
| 1121 | 1122 | /* must be called with netlink table grabbed */ |
| 1122 | 1123 | static void netlink_update_socket_mc(struct netlink_sock *nlk, |
| @@ -61,7 +61,7 @@ static struct ctl_table_root net_sysctl_root = { · 60 unmodified lines | ||
| 61 | 61 | static int net_ctl_ro_header_perms(struct ctl_table_root *root, |
| 62 | 62 | struct nsproxy *namespaces, struct ctl_table *table) |
| 63 | 63 | { |
| 64 | − if (namespaces->net_ns == &init_net) | |
| 64 | + if (net_eq(namespaces->net_ns, &init_net)) | |
| 65 | 65 | return table->mode; |
| 66 | 66 | else |
| 67 | 67 | return table->mode & ~0222; |