fixed netfilter errors and missing dependencies

This commit is contained in:
Danijel Posilovic 2011-02-12 00:58:28 +01:00 committed by tytung
parent d3034284d5
commit 0e29cb4fa1
34 changed files with 793 additions and 2067 deletions

View File

@ -1,208 +0,0 @@
[ NOTE: The virt_to_bus() and bus_to_virt() functions have been
superseded by the functionality provided by the PCI DMA interface
(see Documentation/PCI/PCI-DMA-mapping.txt). They continue
to be documented below for historical purposes, but new code
must not use them. --davidm 00/12/12 ]
[ This is a mail message in response to a query on IO mapping, thus the
strange format for a "document" ]
The AHA-1542 is a bus-master device, and your patch makes the driver give the
controller the physical address of the buffers, which is correct on x86
(because all bus master devices see the physical memory mappings directly).
However, on many setups, there are actually _three_ different ways of looking
at memory addresses, and in this case we actually want the third, the
so-called "bus address".
Essentially, the three ways of addressing memory are (this is "real memory",
that is, normal RAM--see later about other details):
- CPU untranslated. This is the "physical" address. Physical address
0 is what the CPU sees when it drives zeroes on the memory bus.
- CPU translated address. This is the "virtual" address, and is
completely internal to the CPU itself with the CPU doing the appropriate
translations into "CPU untranslated".
- bus address. This is the address of memory as seen by OTHER devices,
not the CPU. Now, in theory there could be many different bus
addresses, with each device seeing memory in some device-specific way, but
happily most hardware designers aren't actually actively trying to make
things any more complex than necessary, so you can assume that all
external hardware sees the memory the same way.
Now, on normal PCs the bus address is exactly the same as the physical
address, and things are very simple indeed. However, they are that simple
because the memory and the devices share the same address space, and that is
not generally necessarily true on other PCI/ISA setups.
Now, just as an example, on the PReP (PowerPC Reference Platform), the
CPU sees a memory map something like this (this is from memory):
0-2 GB "real memory"
2 GB-3 GB "system IO" (inb/out and similar accesses on x86)
3 GB-4 GB "IO memory" (shared memory over the IO bus)
Now, that looks simple enough. However, when you look at the same thing from
the viewpoint of the devices, you have the reverse, and the physical memory
address 0 actually shows up as address 2 GB for any IO master.
So when the CPU wants any bus master to write to physical memory 0, it
has to give the master address 0x80000000 as the memory address.
So, for example, depending on how the kernel is actually mapped on the
PPC, you can end up with a setup like this:
physical address: 0
virtual address: 0xC0000000
bus address: 0x80000000
where all the addresses actually point to the same thing. It's just seen
through different translations..
Similarly, on the Alpha, the normal translation is
physical address: 0
virtual address: 0xfffffc0000000000
bus address: 0x40000000
(but there are also Alphas where the physical address and the bus address
are the same).
Anyway, the way to look up all these translations, you do
#include <asm/io.h>
phys_addr = virt_to_phys(virt_addr);
virt_addr = phys_to_virt(phys_addr);
bus_addr = virt_to_bus(virt_addr);
virt_addr = bus_to_virt(bus_addr);
Now, when do you need these?
You want the _virtual_ address when you are actually going to access that
pointer from the kernel. So you can have something like this:
/*
* this is the hardware "mailbox" we use to communicate with
* the controller. The controller sees this directly.
*/
struct mailbox {
__u32 status;
__u32 bufstart;
__u32 buflen;
..
} mbox;
unsigned char * retbuffer;
/* get the address from the controller */
retbuffer = bus_to_virt(mbox.bufstart);
switch (retbuffer[0]) {
case STATUS_OK:
...
on the other hand, you want the bus address when you have a buffer that
you want to give to the controller:
/* ask the controller to read the sense status into "sense_buffer" */
mbox.bufstart = virt_to_bus(&sense_buffer);
mbox.buflen = sizeof(sense_buffer);
mbox.status = 0;
notify_controller(&mbox);
And you generally _never_ want to use the physical address, because you can't
use that from the CPU (the CPU only uses translated virtual addresses), and
you can't use it from the bus master.
So why do we care about the physical address at all? We do need the physical
address in some cases, it's just not very often in normal code. The physical
address is needed if you use memory mappings, for example, because the
"remap_pfn_range()" mm function wants the physical address of the memory to
be remapped as measured in units of pages, a.k.a. the pfn (the memory
management layer doesn't know about devices outside the CPU, so it
shouldn't need to know about "bus addresses" etc).
NOTE NOTE NOTE! The above is only one part of the whole equation. The above
only talks about "real memory", that is, CPU memory (RAM).
There is a completely different type of memory too, and that's the "shared
memory" on the PCI or ISA bus. That's generally not RAM (although in the case
of a video graphics card it can be normal DRAM that is just used for a frame
buffer), but can be things like a packet buffer in a network card etc.
This memory is called "PCI memory" or "shared memory" or "IO memory" or
whatever, and there is only one way to access it: the readb/writeb and
related functions. You should never take the address of such memory, because
there is really nothing you can do with such an address: it's not
conceptually in the same memory space as "real memory" at all, so you cannot
just dereference a pointer. (Sadly, on x86 it _is_ in the same memory space,
so on x86 it actually works to just deference a pointer, but it's not
portable).
For such memory, you can do things like
- reading:
/*
* read first 32 bits from ISA memory at 0xC0000, aka
* C000:0000 in DOS terms
*/
unsigned int signature = isa_readl(0xC0000);
- remapping and writing:
/*
* remap framebuffer PCI memory area at 0xFC000000,
* size 1MB, so that we can access it: We can directly
* access only the 640k-1MB area, so anything else
* has to be remapped.
*/
char * baseptr = ioremap(0xFC000000, 1024*1024);
/* write a 'A' to the offset 10 of the area */
writeb('A',baseptr+10);
/* unmap when we unload the driver */
iounmap(baseptr);
- copying and clearing:
/* get the 6-byte Ethernet address at ISA address E000:0040 */
memcpy_fromio(kernel_buffer, 0xE0040, 6);
/* write a packet to the driver */
memcpy_toio(0xE1000, skb->data, skb->len);
/* clear the frame buffer */
memset_io(0xA0000, 0, 0x10000);
OK, that just about covers the basics of accessing IO portably. Questions?
Comments? You may think that all the above is overly complex, but one day you
might find yourself with a 500 MHz Alpha in front of you, and then you'll be
happy that your driver works ;)
Note that kernel versions 2.0.x (and earlier) mistakenly called the
ioremap() function "vremap()". ioremap() is the proper name, but I
didn't think straight when I wrote it originally. People who have to
support both can do something like:
/* support old naming silliness */
#if LINUX_VERSION_CODE < 0x020100
#define ioremap vremap
#define iounmap vfree
#endif
at the top of their source files, and then they can use the right names
even on 2.0.x systems.
And the above sounds worse than it really is. Most real drivers really
don't do all that complex things (or rather: the complexity is not so
much in the actual IO accesses as in error handling and timeouts etc).
It's generally not hard to fix drivers, and in many cases the code
actually looks better afterwards:
unsigned long signature = *(unsigned int *) 0xC0000;
vs
unsigned long signature = readl(0xC0000);
I think the second version actually is more readable, no?
Linus

View File

@ -1,82 +1,208 @@
The io_mapping functions in linux/io-mapping.h provide an abstraction for
efficiently mapping small regions of an I/O device to the CPU. The initial
usage is to support the large graphics aperture on 32-bit processors where
ioremap_wc cannot be used to statically map the entire aperture to the CPU
as it would consume too much of the kernel address space.
[ NOTE: The virt_to_bus() and bus_to_virt() functions have been
superseded by the functionality provided by the PCI DMA interface
(see Documentation/PCI/PCI-DMA-mapping.txt). They continue
to be documented below for historical purposes, but new code
must not use them. --davidm 00/12/12 ]
A mapping object is created during driver initialization using
[ This is a mail message in response to a query on IO mapping, thus the
strange format for a "document" ]
struct io_mapping *io_mapping_create_wc(unsigned long base,
unsigned long size)
The AHA-1542 is a bus-master device, and your patch makes the driver give the
controller the physical address of the buffers, which is correct on x86
(because all bus master devices see the physical memory mappings directly).
'base' is the bus address of the region to be made
mappable, while 'size' indicates how large a mapping region to
enable. Both are in bytes.
However, on many setups, there are actually _three_ different ways of looking
at memory addresses, and in this case we actually want the third, the
so-called "bus address".
This _wc variant provides a mapping which may only be used
with the io_mapping_map_atomic_wc or io_mapping_map_wc.
Essentially, the three ways of addressing memory are (this is "real memory",
that is, normal RAM--see later about other details):
With this mapping object, individual pages can be mapped either atomically
or not, depending on the necessary scheduling environment. Of course, atomic
maps are more efficient:
- CPU untranslated. This is the "physical" address. Physical address
0 is what the CPU sees when it drives zeroes on the memory bus.
void *io_mapping_map_atomic_wc(struct io_mapping *mapping,
unsigned long offset)
- CPU translated address. This is the "virtual" address, and is
completely internal to the CPU itself with the CPU doing the appropriate
translations into "CPU untranslated".
'offset' is the offset within the defined mapping region.
Accessing addresses beyond the region specified in the
creation function yields undefined results. Using an offset
which is not page aligned yields an undefined result. The
return value points to a single page in CPU address space.
- bus address. This is the address of memory as seen by OTHER devices,
not the CPU. Now, in theory there could be many different bus
addresses, with each device seeing memory in some device-specific way, but
happily most hardware designers aren't actually actively trying to make
things any more complex than necessary, so you can assume that all
external hardware sees the memory the same way.
This _wc variant returns a write-combining map to the
page and may only be used with mappings created by
io_mapping_create_wc
Now, on normal PCs the bus address is exactly the same as the physical
address, and things are very simple indeed. However, they are that simple
because the memory and the devices share the same address space, and that is
not generally necessarily true on other PCI/ISA setups.
Note that the task may not sleep while holding this page
mapped.
Now, just as an example, on the PReP (PowerPC Reference Platform), the
CPU sees a memory map something like this (this is from memory):
void io_mapping_unmap_atomic(void *vaddr)
0-2 GB "real memory"
2 GB-3 GB "system IO" (inb/out and similar accesses on x86)
3 GB-4 GB "IO memory" (shared memory over the IO bus)
'vaddr' must be the the value returned by the last
io_mapping_map_atomic_wc call. This unmaps the specified
page and allows the task to sleep once again.
Now, that looks simple enough. However, when you look at the same thing from
the viewpoint of the devices, you have the reverse, and the physical memory
address 0 actually shows up as address 2 GB for any IO master.
If you need to sleep while holding the lock, you can use the non-atomic
variant, although they may be significantly slower.
So when the CPU wants any bus master to write to physical memory 0, it
has to give the master address 0x80000000 as the memory address.
void *io_mapping_map_wc(struct io_mapping *mapping,
unsigned long offset)
So, for example, depending on how the kernel is actually mapped on the
PPC, you can end up with a setup like this:
This works like io_mapping_map_atomic_wc except it allows
the task to sleep while holding the page mapped.
physical address: 0
virtual address: 0xC0000000
bus address: 0x80000000
void io_mapping_unmap(void *vaddr)
where all the addresses actually point to the same thing. It's just seen
through different translations..
This works like io_mapping_unmap_atomic, except it is used
for pages mapped with io_mapping_map_wc.
Similarly, on the Alpha, the normal translation is
At driver close time, the io_mapping object must be freed:
physical address: 0
virtual address: 0xfffffc0000000000
bus address: 0x40000000
void io_mapping_free(struct io_mapping *mapping)
(but there are also Alphas where the physical address and the bus address
are the same).
Current Implementation:
Anyway, the way to look up all these translations, you do
The initial implementation of these functions uses existing mapping
mechanisms and so provides only an abstraction layer and no new
functionality.
#include <asm/io.h>
On 64-bit processors, io_mapping_create_wc calls ioremap_wc for the whole
range, creating a permanent kernel-visible mapping to the resource. The
map_atomic and map functions add the requested offset to the base of the
virtual address returned by ioremap_wc.
phys_addr = virt_to_phys(virt_addr);
virt_addr = phys_to_virt(phys_addr);
bus_addr = virt_to_bus(virt_addr);
virt_addr = bus_to_virt(bus_addr);
On 32-bit processors with HIGHMEM defined, io_mapping_map_atomic_wc uses
kmap_atomic_pfn to map the specified page in an atomic fashion;
kmap_atomic_pfn isn't really supposed to be used with device pages, but it
provides an efficient mapping for this usage.
Now, when do you need these?
You want the _virtual_ address when you are actually going to access that
pointer from the kernel. So you can have something like this:
/*
* this is the hardware "mailbox" we use to communicate with
* the controller. The controller sees this directly.
*/
struct mailbox {
__u32 status;
__u32 bufstart;
__u32 buflen;
..
} mbox;
unsigned char * retbuffer;
/* get the address from the controller */
retbuffer = bus_to_virt(mbox.bufstart);
switch (retbuffer[0]) {
case STATUS_OK:
...
on the other hand, you want the bus address when you have a buffer that
you want to give to the controller:
/* ask the controller to read the sense status into "sense_buffer" */
mbox.bufstart = virt_to_bus(&sense_buffer);
mbox.buflen = sizeof(sense_buffer);
mbox.status = 0;
notify_controller(&mbox);
And you generally _never_ want to use the physical address, because you can't
use that from the CPU (the CPU only uses translated virtual addresses), and
you can't use it from the bus master.
So why do we care about the physical address at all? We do need the physical
address in some cases, it's just not very often in normal code. The physical
address is needed if you use memory mappings, for example, because the
"remap_pfn_range()" mm function wants the physical address of the memory to
be remapped as measured in units of pages, a.k.a. the pfn (the memory
management layer doesn't know about devices outside the CPU, so it
shouldn't need to know about "bus addresses" etc).
NOTE NOTE NOTE! The above is only one part of the whole equation. The above
only talks about "real memory", that is, CPU memory (RAM).
There is a completely different type of memory too, and that's the "shared
memory" on the PCI or ISA bus. That's generally not RAM (although in the case
of a video graphics card it can be normal DRAM that is just used for a frame
buffer), but can be things like a packet buffer in a network card etc.
This memory is called "PCI memory" or "shared memory" or "IO memory" or
whatever, and there is only one way to access it: the readb/writeb and
related functions. You should never take the address of such memory, because
there is really nothing you can do with such an address: it's not
conceptually in the same memory space as "real memory" at all, so you cannot
just dereference a pointer. (Sadly, on x86 it _is_ in the same memory space,
so on x86 it actually works to just deference a pointer, but it's not
portable).
For such memory, you can do things like
- reading:
/*
* read first 32 bits from ISA memory at 0xC0000, aka
* C000:0000 in DOS terms
*/
unsigned int signature = isa_readl(0xC0000);
- remapping and writing:
/*
* remap framebuffer PCI memory area at 0xFC000000,
* size 1MB, so that we can access it: We can directly
* access only the 640k-1MB area, so anything else
* has to be remapped.
*/
char * baseptr = ioremap(0xFC000000, 1024*1024);
/* write a 'A' to the offset 10 of the area */
writeb('A',baseptr+10);
/* unmap when we unload the driver */
iounmap(baseptr);
- copying and clearing:
/* get the 6-byte Ethernet address at ISA address E000:0040 */
memcpy_fromio(kernel_buffer, 0xE0040, 6);
/* write a packet to the driver */
memcpy_toio(0xE1000, skb->data, skb->len);
/* clear the frame buffer */
memset_io(0xA0000, 0, 0x10000);
OK, that just about covers the basics of accessing IO portably. Questions?
Comments? You may think that all the above is overly complex, but one day you
might find yourself with a 500 MHz Alpha in front of you, and then you'll be
happy that your driver works ;)
Note that kernel versions 2.0.x (and earlier) mistakenly called the
ioremap() function "vremap()". ioremap() is the proper name, but I
didn't think straight when I wrote it originally. People who have to
support both can do something like:
/* support old naming silliness */
#if LINUX_VERSION_CODE < 0x020100
#define ioremap vremap
#define iounmap vfree
#endif
at the top of their source files, and then they can use the right names
even on 2.0.x systems.
And the above sounds worse than it really is. Most real drivers really
don't do all that complex things (or rather: the complexity is not so
much in the actual IO accesses as in error handling and timeouts etc).
It's generally not hard to fix drivers, and in many cases the code
actually looks better afterwards:
unsigned long signature = *(unsigned int *) 0xC0000;
vs
unsigned long signature = readl(0xC0000);
I think the second version actually is more readable, no?
Linus
On 32-bit processors without HIGHMEM defined, io_mapping_map_atomic_wc and
io_mapping_map_wc both use ioremap_wc, a terribly inefficient function which
performs an IPI to inform all processors about the new mapping. This results
in a significant performance penalty.

View File

@ -1 +0,0 @@
../../platform/generic/system.dts

View File

@ -1,5 +1,5 @@
#ifndef _XT_CONNMARK_H_target
#define _XT_CONNMARK_H_target
#ifndef _XT_CONNMARK_H
#define _XT_CONNMARK_H
#include <linux/types.h>
@ -12,15 +12,20 @@
* (at your option) any later version.
*/
enum {
XT_CONNMARK_SET = 0,
XT_CONNMARK_SAVE,
XT_CONNMARK_RESTORE
enum {
XT_CONNMARK_SET = 0,
XT_CONNMARK_SAVE,
XT_CONNMARK_RESTORE
};
struct xt_connmark_tginfo1 {
__u32 ctmark, ctmask, nfmask;
__u8 mode;
};
struct xt_connmark_mtinfo1 {
__u32 mark, mask;
__u8 invert;
};
struct xt_connmark_tginfo1 {
__u32 ctmark, ctmask, nfmask;
__u8 mode;
};
#endif /*_XT_CONNMARK_H_target*/
#endif /*_XT_CONNMARK_H*/

View File

@ -1,26 +0,0 @@
/* x_tables module for setting the IPv4/IPv6 DSCP field
*
* (C) 2002 Harald Welte <laforge@gnumonks.org>
* based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
* This software is distributed under GNU GPL v2, 1991
*
* See RFC2474 for a description of the DSCP field within the IP Header.
*
* xt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
*/
#ifndef _XT_DSCP_TARGET_H
#define _XT_DSCP_TARGET_H
#include <linux/netfilter/xt_dscp.h>
#include <linux/types.h>
/* target info */
struct xt_DSCP_info {
__u8 dscp;
};
struct xt_tos_target_info {
__u8 tos_value;
__u8 tos_mask;
};
#endif /* _XT_DSCP_TARGET_H */

View File

@ -1,10 +0,0 @@
#ifndef _XT_MARK_H_target
#define _XT_MARK_H_target
#include <linux/types.h>
struct xt_mark_tginfo2 {
__u32 mark, mask;
};
#endif /*_XT_MARK_H_target */

View File

@ -1,15 +1,37 @@
#ifndef _XT_RATEEST_TARGET_H
#define _XT_RATEEST_TARGET_H
#ifndef _XT_RATEEST_MATCH_H
#define _XT_RATEEST_MATCH_H
#include <linux/types.h>
struct xt_rateest_target_info {
char name[IFNAMSIZ];
__s8 interval;
__u8 ewma_log;
/* Used internally by the kernel */
struct xt_rateest *est __attribute__((aligned(8)));
enum xt_rateest_match_flags {
XT_RATEEST_MATCH_INVERT = 1<<0,
XT_RATEEST_MATCH_ABS = 1<<1,
XT_RATEEST_MATCH_REL = 1<<2,
XT_RATEEST_MATCH_DELTA = 1<<3,
XT_RATEEST_MATCH_BPS = 1<<4,
XT_RATEEST_MATCH_PPS = 1<<5,
};
#endif /* _XT_RATEEST_TARGET_H */
enum xt_rateest_match_mode {
XT_RATEEST_MATCH_NONE,
XT_RATEEST_MATCH_EQ,
XT_RATEEST_MATCH_LT,
XT_RATEEST_MATCH_GT,
};
struct xt_rateest_match_info {
char name1[IFNAMSIZ];
char name2[IFNAMSIZ];
__u16 flags;
__u16 mode;
__u32 bps1;
__u32 pps1;
__u32 bps2;
__u32 pps2;
/* Used internally by the kernel */
struct xt_rateest *est1 __attribute__((aligned(8)));
struct xt_rateest *est2 __attribute__((aligned(8)));
};
#endif /* _XT_RATEEST_MATCH_H */

View File

@ -1,12 +1,11 @@
#ifndef _XT_TCPMSS_H
#define _XT_TCPMSS_H
#ifndef _XT_TCPMSS_MATCH_H
#define _XT_TCPMSS_MATCH_H
#include <linux/types.h>
struct xt_tcpmss_info {
__u16 mss;
struct xt_tcpmss_match_info {
__u16 mss_min, mss_max;
__u8 invert;
};
#define XT_TCPMSS_CLAMP_PMTU 0xffff
#endif /* _XT_TCPMSS_H */
#endif /*_XT_TCPMSS_MATCH_H*/

View File

@ -1,20 +0,0 @@
#ifndef _XT_CONNMARK_H
#define _XT_CONNMARK_H
#include <linux/types.h>
/* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
* by Henrik Nordstrom <hno@marasystems.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*/
struct xt_connmark_mtinfo1 {
__u32 mark, mask;
__u8 invert;
};
#endif /*_XT_CONNMARK_H*/

View File

@ -1,31 +1,30 @@
/* x_tables module for matching the IPv4/IPv6 DSCP field
/* x_tables module for setting the IPv4/IPv6 DSCP field
*
* (C) 2002 Harald Welte <laforge@gnumonks.org>
* based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
* This software is distributed under GNU GPL v2, 1991
*
* See RFC2474 for a description of the DSCP field within the IP Header.
*
* xt_dscp.h,v 1.3 2002/08/05 19:00:21 laforge Exp
* xt_DSCP.h,v 1.7 2002/03/14 12:03:13 laforge Exp
*/
#ifndef _XT_DSCP_H
#define _XT_DSCP_H
#ifndef _XT_DSCP_TARGET_H
#define _XT_DSCP_TARGET_H
#include <linux/netfilter/xt_dscp.h>
#include <linux/types.h>
#define XT_DSCP_MASK 0xfc /* 11111100 */
#define XT_DSCP_SHIFT 2
#define XT_DSCP_MAX 0x3f /* 00111111 */
#define XT_DSCP_MASK 0xfc /* 11111100 */
#define XT_DSCP_SHIFT 2
#define XT_DSCP_MAX 0x3f /* 00111111 */
/* match info */
struct xt_dscp_info {
/* target info */
struct xt_DSCP_info {
__u8 dscp;
__u8 invert;
};
struct xt_tos_match_info {
__u8 tos_mask;
struct xt_tos_target_info {
__u8 tos_value;
__u8 invert;
__u8 tos_mask;
};
#endif /* _XT_DSCP_H */
#endif /* _XT_DSCP_TARGET_H */

View File

@ -1,11 +1,10 @@
#ifndef _XT_MARK_H
#define _XT_MARK_H
#ifndef _XT_MARK_H_target
#define _XT_MARK_H_target
#include <linux/types.h>
struct xt_mark_mtinfo1 {
struct xt_mark_tginfo2 {
__u32 mark, mask;
__u8 invert;
};
#endif /*_XT_MARK_H*/
#endif /*_XT_MARK_H_target */

View File

@ -1,37 +0,0 @@
#ifndef _XT_RATEEST_MATCH_H
#define _XT_RATEEST_MATCH_H
#include <linux/types.h>
enum xt_rateest_match_flags {
XT_RATEEST_MATCH_INVERT = 1<<0,
XT_RATEEST_MATCH_ABS = 1<<1,
XT_RATEEST_MATCH_REL = 1<<2,
XT_RATEEST_MATCH_DELTA = 1<<3,
XT_RATEEST_MATCH_BPS = 1<<4,
XT_RATEEST_MATCH_PPS = 1<<5,
};
enum xt_rateest_match_mode {
XT_RATEEST_MATCH_NONE,
XT_RATEEST_MATCH_EQ,
XT_RATEEST_MATCH_LT,
XT_RATEEST_MATCH_GT,
};
struct xt_rateest_match_info {
char name1[IFNAMSIZ];
char name2[IFNAMSIZ];
__u16 flags;
__u16 mode;
__u32 bps1;
__u32 pps1;
__u32 bps2;
__u32 pps2;
/* Used internally by the kernel */
struct xt_rateest *est1 __attribute__((aligned(8)));
struct xt_rateest *est2 __attribute__((aligned(8)));
};
#endif /* _XT_RATEEST_MATCH_H */

View File

@ -1,11 +0,0 @@
#ifndef _XT_TCPMSS_MATCH_H
#define _XT_TCPMSS_MATCH_H
#include <linux/types.h>
struct xt_tcpmss_match_info {
__u16 mss_min, mss_max;
__u8 invert;
};
#endif /*_XT_TCPMSS_MATCH_H*/

View File

@ -1,31 +1,33 @@
/* Header file for iptables ipt_ECN target
/* iptables module for matching the ECN header in IPv4 and TCP header
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
* (C) 2002 Harald Welte <laforge@gnumonks.org>
*
* This software is distributed under GNU GPL v2, 1991
*
* ipt_ECN.h,v 1.3 2002/05/29 12:17:40 laforge Exp
* ipt_ecn.h,v 1.4 2002/08/05 19:39:00 laforge Exp
*/
#ifndef _IPT_ECN_TARGET_H
#define _IPT_ECN_TARGET_H
#include <linux/netfilter/xt_DSCP.h>
#ifndef _IPT_ECN_H
#define _IPT_ECN_H
#include <linux/netfilter/xt_dscp.h>
#define IPT_ECN_IP_MASK (~XT_DSCP_MASK)
#define IPT_ECN_OP_SET_IP 0x01 /* set ECN bits of IPv4 header */
#define IPT_ECN_OP_SET_ECE 0x10 /* set ECE bit of TCP header */
#define IPT_ECN_OP_SET_CWR 0x20 /* set CWR bit of TCP header */
#define IPT_ECN_OP_MATCH_IP 0x01
#define IPT_ECN_OP_MATCH_ECE 0x10
#define IPT_ECN_OP_MATCH_CWR 0x20
#define IPT_ECN_OP_MASK 0xce
#define IPT_ECN_OP_MATCH_MASK 0xce
struct ipt_ECN_info {
u_int8_t operation; /* bitset of operations */
u_int8_t ip_ect; /* ECT codepoint of IPv4 header, pre-shifted */
/* match info */
struct ipt_ecn_info {
u_int8_t operation;
u_int8_t invert;
u_int8_t ip_ect;
union {
struct {
u_int8_t ece:1, cwr:1; /* TCP ECT bits */
u_int8_t ect;
} tcp;
} proto;
};
#endif /* _IPT_ECN_TARGET_H */
#endif /* _IPT_ECN_H */

View File

@ -1,18 +1,18 @@
/* TTL modification module for IP tables
* (C) 2000 by Harald Welte <laforge@netfilter.org> */
/* IP tables module for matching the value of the TTL
* (C) 2000 by Harald Welte <laforge@gnumonks.org> */
#ifndef _IPT_TTL_H
#define _IPT_TTL_H
enum {
IPT_TTL_SET = 0,
IPT_TTL_INC,
IPT_TTL_DEC
IPT_TTL_EQ = 0, /* equals */
IPT_TTL_NE, /* not equals */
IPT_TTL_LT, /* less than */
IPT_TTL_GT, /* greater than */
};
#define IPT_TTL_MAXMODE IPT_TTL_DEC
struct ipt_TTL_info {
struct ipt_ttl_info {
u_int8_t mode;
u_int8_t ttl;
};

View File

@ -1,33 +0,0 @@
/* iptables module for matching the ECN header in IPv4 and TCP header
*
* (C) 2002 Harald Welte <laforge@gnumonks.org>
*
* This software is distributed under GNU GPL v2, 1991
*
* ipt_ecn.h,v 1.4 2002/08/05 19:39:00 laforge Exp
*/
#ifndef _IPT_ECN_H
#define _IPT_ECN_H
#include <linux/netfilter/xt_dscp.h>
#define IPT_ECN_IP_MASK (~XT_DSCP_MASK)
#define IPT_ECN_OP_MATCH_IP 0x01
#define IPT_ECN_OP_MATCH_ECE 0x10
#define IPT_ECN_OP_MATCH_CWR 0x20
#define IPT_ECN_OP_MATCH_MASK 0xce
/* match info */
struct ipt_ecn_info {
u_int8_t operation;
u_int8_t invert;
u_int8_t ip_ect;
union {
struct {
u_int8_t ect;
} tcp;
} proto;
};
#endif /* _IPT_ECN_H */

View File

@ -1,21 +0,0 @@
/* IP tables module for matching the value of the TTL
* (C) 2000 by Harald Welte <laforge@gnumonks.org> */
#ifndef _IPT_TTL_H
#define _IPT_TTL_H
enum {
IPT_TTL_EQ = 0, /* equals */
IPT_TTL_NE, /* not equals */
IPT_TTL_LT, /* less than */
IPT_TTL_GT, /* greater than */
};
struct ipt_ttl_info {
u_int8_t mode;
u_int8_t ttl;
};
#endif

View File

@ -1,19 +1,19 @@
/* Hop Limit modification module for ip6tables
/* ip6tables module for matching the Hop Limit value
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
* Based on HW's TTL module */
* Based on HW's ttl module */
#ifndef _IP6T_HL_H
#define _IP6T_HL_H
enum {
IP6T_HL_SET = 0,
IP6T_HL_INC,
IP6T_HL_DEC
IP6T_HL_EQ = 0, /* equals */
IP6T_HL_NE, /* not equals */
IP6T_HL_LT, /* less than */
IP6T_HL_GT, /* greater than */
};
#define IP6T_HL_MAXMODE IP6T_HL_DEC
struct ip6t_HL_info {
struct ip6t_hl_info {
u_int8_t mode;
u_int8_t hop_limit;
};

View File

@ -1,22 +0,0 @@
/* ip6tables module for matching the Hop Limit value
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
* Based on HW's ttl module */
#ifndef _IP6T_HL_H
#define _IP6T_HL_H
enum {
IP6T_HL_EQ = 0, /* equals */
IP6T_HL_NE, /* not equals */
IP6T_HL_LT, /* less than */
IP6T_HL_GT, /* greater than */
};
struct ip6t_hl_info {
u_int8_t mode;
u_int8_t hop_limit;
};
#endif

View File

@ -1,141 +0,0 @@
/* iptables module for the IPv4 and TCP ECN bits, Version 1.5
*
* (C) 2002 by Harald Welte <laforge@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/in.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <linux/tcp.h>
#include <net/checksum.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_ECN.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag modification");
/* set ECT codepoint from IP header.
* return false if there was an error. */
static inline bool
set_ect_ip(struct sk_buff *skb, const struct ipt_ECN_info *einfo)
{
struct iphdr *iph = ip_hdr(skb);
if ((iph->tos & IPT_ECN_IP_MASK) != (einfo->ip_ect & IPT_ECN_IP_MASK)) {
__u8 oldtos;
if (!skb_make_writable(skb, sizeof(struct iphdr)))
return false;
iph = ip_hdr(skb);
oldtos = iph->tos;
iph->tos &= ~IPT_ECN_IP_MASK;
iph->tos |= (einfo->ip_ect & IPT_ECN_IP_MASK);
csum_replace2(&iph->check, htons(oldtos), htons(iph->tos));
}
return true;
}
/* Return false if there was an error. */
static inline bool
set_ect_tcp(struct sk_buff *skb, const struct ipt_ECN_info *einfo)
{
struct tcphdr _tcph, *tcph;
__be16 oldval;
/* Not enought header? */
tcph = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
if (!tcph)
return false;
if ((!(einfo->operation & IPT_ECN_OP_SET_ECE) ||
tcph->ece == einfo->proto.tcp.ece) &&
(!(einfo->operation & IPT_ECN_OP_SET_CWR) ||
tcph->cwr == einfo->proto.tcp.cwr))
return true;
if (!skb_make_writable(skb, ip_hdrlen(skb) + sizeof(*tcph)))
return false;
tcph = (void *)ip_hdr(skb) + ip_hdrlen(skb);
oldval = ((__be16 *)tcph)[6];
if (einfo->operation & IPT_ECN_OP_SET_ECE)
tcph->ece = einfo->proto.tcp.ece;
if (einfo->operation & IPT_ECN_OP_SET_CWR)
tcph->cwr = einfo->proto.tcp.cwr;
inet_proto_csum_replace2(&tcph->check, skb,
oldval, ((__be16 *)tcph)[6], 0);
return true;
}
static unsigned int
ecn_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct ipt_ECN_info *einfo = par->targinfo;
if (einfo->operation & IPT_ECN_OP_SET_IP)
if (!set_ect_ip(skb, einfo))
return NF_DROP;
if (einfo->operation & (IPT_ECN_OP_SET_ECE | IPT_ECN_OP_SET_CWR)
&& ip_hdr(skb)->protocol == IPPROTO_TCP)
if (!set_ect_tcp(skb, einfo))
return NF_DROP;
return XT_CONTINUE;
}
static bool ecn_tg_check(const struct xt_tgchk_param *par)
{
const struct ipt_ECN_info *einfo = par->targinfo;
const struct ipt_entry *e = par->entryinfo;
if (einfo->operation & IPT_ECN_OP_MASK) {
printk(KERN_WARNING "ECN: unsupported ECN operation %x\n",
einfo->operation);
return false;
}
if (einfo->ip_ect & ~IPT_ECN_IP_MASK) {
printk(KERN_WARNING "ECN: new ECT codepoint %x out of mask\n",
einfo->ip_ect);
return false;
}
if ((einfo->operation & (IPT_ECN_OP_SET_ECE|IPT_ECN_OP_SET_CWR))
&& (e->ip.proto != IPPROTO_TCP || (e->ip.invflags & XT_INV_PROTO))) {
printk(KERN_WARNING "ECN: cannot use TCP operations on a "
"non-tcp rule\n");
return false;
}
return true;
}
static struct xt_target ecn_tg_reg __read_mostly = {
.name = "ECN",
.family = NFPROTO_IPV4,
.target = ecn_tg,
.targetsize = sizeof(struct ipt_ECN_info),
.table = "mangle",
.checkentry = ecn_tg_check,
.me = THIS_MODULE,
};
static int __init ecn_tg_init(void)
{
return xt_register_target(&ecn_tg_reg);
}
static void __exit ecn_tg_exit(void)
{
xt_unregister_target(&ecn_tg_reg);
}
module_init(ecn_tg_init);
module_exit(ecn_tg_exit);

View File

@ -1,129 +1,129 @@
/* IP tables module for matching the value of the IPv4 and TCP ECN bits
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
/* IP tables module for matching the value of the IPv4 and TCP ECN bits
*
* (C) 2002 by Harald Welte <laforge@gnumonks.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/in.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_ECN.h>
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match for IPv4");
MODULE_LICENSE("GPL");
static inline bool match_ip(const struct sk_buff *skb,
const struct ipt_ecn_info *einfo)
{
return (ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect;
}
static inline bool match_tcp(const struct sk_buff *skb,
const struct ipt_ecn_info *einfo,
bool *hotdrop)
{
struct tcphdr _tcph;
const struct tcphdr *th;
#include <linux/in.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/tcp.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_ecn.h>
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("Xtables: Explicit Congestion Notification (ECN) flag match for IPv4");
MODULE_LICENSE("GPL");
static inline bool match_ip(const struct sk_buff *skb,
const struct ipt_ecn_info *einfo)
{
return (ip_hdr(skb)->tos & IPT_ECN_IP_MASK) == einfo->ip_ect;
}
static inline bool match_tcp(const struct sk_buff *skb,
const struct ipt_ecn_info *einfo,
bool *hotdrop)
{
struct tcphdr _tcph;
const struct tcphdr *th;
/* In practice, TCP match does this, so can't fail. But let's
* be good citizens.
*/
th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
if (th == NULL) {
*hotdrop = false;
return false;
}
if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
if (th->ece == 1)
return false;
} else {
if (th->ece == 0)
return false;
}
}
if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
if (th->cwr == 1)
return false;
} else {
if (th->cwr == 0)
return false;
}
}
return true;
}
static bool ecn_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
const struct ipt_ecn_info *info = par->matchinfo;
if (info->operation & IPT_ECN_OP_MATCH_IP)
if (!match_ip(skb, info))
return false;
if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
if (ip_hdr(skb)->protocol != IPPROTO_TCP)
return false;
if (!match_tcp(skb, info, par->hotdrop))
return false;
}
return true;
}
static bool ecn_mt_check(const struct xt_mtchk_param *par)
{
const struct ipt_ecn_info *info = par->matchinfo;
const struct ipt_ip *ip = par->entryinfo;
if (info->operation & IPT_ECN_OP_MATCH_MASK)
return false;
if (info->invert & IPT_ECN_OP_MATCH_MASK)
return false;
if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
&& ip->proto != IPPROTO_TCP) {
printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
" non-tcp packets\n");
return false;
}
return true;
}
static struct xt_match ecn_mt_reg __read_mostly = {
.name = "ecn",
.family = NFPROTO_IPV4,
.match = ecn_mt,
.matchsize = sizeof(struct ipt_ecn_info),
.checkentry = ecn_mt_check,
.me = THIS_MODULE,
};
static int __init ecn_mt_init(void)
{
return xt_register_match(&ecn_mt_reg);
}
static void __exit ecn_mt_exit(void)
{
xt_unregister_match(&ecn_mt_reg);
}
module_init(ecn_mt_init);
module_exit(ecn_mt_exit);
/* In practice, TCP match does this, so can't fail. But let's
* be good citizens.
*/
th = skb_header_pointer(skb, ip_hdrlen(skb), sizeof(_tcph), &_tcph);
if (th == NULL) {
*hotdrop = false;
return false;
}
if (einfo->operation & IPT_ECN_OP_MATCH_ECE) {
if (einfo->invert & IPT_ECN_OP_MATCH_ECE) {
if (th->ece == 1)
return false;
} else {
if (th->ece == 0)
return false;
}
}
if (einfo->operation & IPT_ECN_OP_MATCH_CWR) {
if (einfo->invert & IPT_ECN_OP_MATCH_CWR) {
if (th->cwr == 1)
return false;
} else {
if (th->cwr == 0)
return false;
}
}
return true;
}
static bool ecn_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
const struct ipt_ecn_info *info = par->matchinfo;
if (info->operation & IPT_ECN_OP_MATCH_IP)
if (!match_ip(skb, info))
return false;
if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)) {
if (ip_hdr(skb)->protocol != IPPROTO_TCP)
return false;
if (!match_tcp(skb, info, par->hotdrop))
return false;
}
return true;
}
static bool ecn_mt_check(const struct xt_mtchk_param *par)
{
const struct ipt_ecn_info *info = par->matchinfo;
const struct ipt_ip *ip = par->entryinfo;
if (info->operation & IPT_ECN_OP_MATCH_MASK)
return false;
if (info->invert & IPT_ECN_OP_MATCH_MASK)
return false;
if (info->operation & (IPT_ECN_OP_MATCH_ECE|IPT_ECN_OP_MATCH_CWR)
&& ip->proto != IPPROTO_TCP) {
printk(KERN_WARNING "ipt_ecn: can't match TCP bits in rule for"
" non-tcp packets\n");
return false;
}
return true;
}
static struct xt_match ecn_mt_reg __read_mostly = {
.name = "ecn",
.family = NFPROTO_IPV4,
.match = ecn_mt,
.matchsize = sizeof(struct ipt_ecn_info),
.checkentry = ecn_mt_check,
.me = THIS_MODULE,
};
static int __init ecn_mt_init(void)
{
return xt_register_match(&ecn_mt_reg);
}
static void __exit ecn_mt_exit(void)
{
xt_unregister_match(&ecn_mt_reg);
}
module_init(ecn_mt_init);
module_exit(ecn_mt_exit);

View File

@ -42,12 +42,12 @@ obj-$(CONFIG_NETFILTER_XTABLES) += x_tables.o xt_tcpudp.o
# targets
obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIFY) += xt_CLASSIFY.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_CONNMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNMARK) += xt_connmark.o
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_hl.o
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_MARK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_MARK) += xt_mark.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFLOG) += xt_NFLOG.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE) += xt_NFQUEUE.o
obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o

View File

@ -1,113 +0,0 @@
/*
* xt_CONNMARK - Netfilter module to modify the connection mark values
*
* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
* by Henrik Nordstrom <hno@marasystems.com>
* Copyright © CC Computer Consultants GmbH, 2007 - 2008
* Jan Engelhardt <jengelh@computergmbh.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/checksum.h>
MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>");
MODULE_DESCRIPTION("Xtables: connection mark modification");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_CONNMARK");
MODULE_ALIAS("ip6t_CONNMARK");
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_CONNMARK.h>
#include <net/netfilter/nf_conntrack_ecache.h>
static unsigned int
connmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_connmark_tginfo1 *info = par->targinfo;
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;
u_int32_t newmark;
ct = nf_ct_get(skb, &ctinfo);
if (ct == NULL)
return XT_CONTINUE;
switch (info->mode) {
case XT_CONNMARK_SET:
newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
if (ct->mark != newmark) {
ct->mark = newmark;
nf_conntrack_event_cache(IPCT_MARK, ct);
}
break;
case XT_CONNMARK_SAVE:
newmark = (ct->mark & ~info->ctmask) ^
(skb->mark & info->nfmask);
if (ct->mark != newmark) {
ct->mark = newmark;
nf_conntrack_event_cache(IPCT_MARK, ct);
}
break;
case XT_CONNMARK_RESTORE:
newmark = (skb->mark & ~info->nfmask) ^
(ct->mark & info->ctmask);
skb->mark = newmark;
break;
}
return XT_CONTINUE;
}
static bool connmark_tg_check(const struct xt_tgchk_param *par)
{
if (nf_ct_l3proto_try_module_get(par->family) < 0) {
printk(KERN_WARNING "cannot load conntrack support for "
"proto=%u\n", par->family);
return false;
}
return true;
}
static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
{
nf_ct_l3proto_module_put(par->family);
}
static struct xt_target connmark_tg_reg __read_mostly = {
.name = "CONNMARK",
.revision = 1,
.family = NFPROTO_UNSPEC,
.checkentry = connmark_tg_check,
.target = connmark_tg,
.targetsize = sizeof(struct xt_connmark_tginfo1),
.destroy = connmark_tg_destroy,
.me = THIS_MODULE,
};
static int __init connmark_tg_init(void)
{
return xt_register_target(&connmark_tg_reg);
}
static void __exit connmark_tg_exit(void)
{
xt_unregister_target(&connmark_tg_reg);
}
module_init(connmark_tg_init);
module_exit(connmark_tg_exit);

View File

@ -1,164 +0,0 @@
/* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8
*
* (C) 2002 by Harald Welte <laforge@netfilter.org>
* based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* See RFC2474 for a description of the DSCP field within the IP Header.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/dsfield.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_DSCP.h>
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_DSCP");
MODULE_ALIAS("ip6t_DSCP");
MODULE_ALIAS("ipt_TOS");
MODULE_ALIAS("ip6t_TOS");
static unsigned int
dscp_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_DSCP_info *dinfo = par->targinfo;
u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
if (dscp != dinfo->dscp) {
if (!skb_make_writable(skb, sizeof(struct iphdr)))
return NF_DROP;
ipv4_change_dsfield(ip_hdr(skb), (__u8)(~XT_DSCP_MASK),
dinfo->dscp << XT_DSCP_SHIFT);
}
return XT_CONTINUE;
}
static unsigned int
dscp_tg6(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_DSCP_info *dinfo = par->targinfo;
u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
if (dscp != dinfo->dscp) {
if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
return NF_DROP;
ipv6_change_dsfield(ipv6_hdr(skb), (__u8)(~XT_DSCP_MASK),
dinfo->dscp << XT_DSCP_SHIFT);
}
return XT_CONTINUE;
}
static bool dscp_tg_check(const struct xt_tgchk_param *par)
{
const struct xt_DSCP_info *info = par->targinfo;
if (info->dscp > XT_DSCP_MAX) {
printk(KERN_WARNING "DSCP: dscp %x out of range\n", info->dscp);
return false;
}
return true;
}
static unsigned int
tos_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_tos_target_info *info = par->targinfo;
struct iphdr *iph = ip_hdr(skb);
u_int8_t orig, nv;
orig = ipv4_get_dsfield(iph);
nv = (orig & ~info->tos_mask) ^ info->tos_value;
if (orig != nv) {
if (!skb_make_writable(skb, sizeof(struct iphdr)))
return NF_DROP;
iph = ip_hdr(skb);
ipv4_change_dsfield(iph, 0, nv);
}
return XT_CONTINUE;
}
static unsigned int
tos_tg6(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_tos_target_info *info = par->targinfo;
struct ipv6hdr *iph = ipv6_hdr(skb);
u_int8_t orig, nv;
orig = ipv6_get_dsfield(iph);
nv = (orig & info->tos_mask) ^ info->tos_value;
if (orig != nv) {
if (!skb_make_writable(skb, sizeof(struct iphdr)))
return NF_DROP;
iph = ipv6_hdr(skb);
ipv6_change_dsfield(iph, 0, nv);
}
return XT_CONTINUE;
}
static struct xt_target dscp_tg_reg[] __read_mostly = {
{
.name = "DSCP",
.family = NFPROTO_IPV4,
.checkentry = dscp_tg_check,
.target = dscp_tg,
.targetsize = sizeof(struct xt_DSCP_info),
.table = "mangle",
.me = THIS_MODULE,
},
{
.name = "DSCP",
.family = NFPROTO_IPV6,
.checkentry = dscp_tg_check,
.target = dscp_tg6,
.targetsize = sizeof(struct xt_DSCP_info),
.table = "mangle",
.me = THIS_MODULE,
},
{
.name = "TOS",
.revision = 1,
.family = NFPROTO_IPV4,
.table = "mangle",
.target = tos_tg,
.targetsize = sizeof(struct xt_tos_target_info),
.me = THIS_MODULE,
},
{
.name = "TOS",
.revision = 1,
.family = NFPROTO_IPV6,
.table = "mangle",
.target = tos_tg6,
.targetsize = sizeof(struct xt_tos_target_info),
.me = THIS_MODULE,
},
};
static int __init dscp_tg_init(void)
{
return xt_register_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg));
}
static void __exit dscp_tg_exit(void)
{
xt_unregister_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg));
}
module_init(dscp_tg_init);
module_exit(dscp_tg_exit);

View File

@ -1,171 +0,0 @@
/*
* TTL modification target for IP tables
* (C) 2000,2005 by Harald Welte <laforge@netfilter.org>
*
* Hop Limit modification target for ip6tables
* Maciej Soltysiak <solt@dns.toxicfilms.tv>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <net/checksum.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_TTL.h>
#include <linux/netfilter_ipv6/ip6t_HL.h>
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
MODULE_DESCRIPTION("Xtables: Hoplimit/TTL Limit field modification target");
MODULE_LICENSE("GPL");
static unsigned int
ttl_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
struct iphdr *iph;
const struct ipt_TTL_info *info = par->targinfo;
int new_ttl;
if (!skb_make_writable(skb, skb->len))
return NF_DROP;
iph = ip_hdr(skb);
switch (info->mode) {
case IPT_TTL_SET:
new_ttl = info->ttl;
break;
case IPT_TTL_INC:
new_ttl = iph->ttl + info->ttl;
if (new_ttl > 255)
new_ttl = 255;
break;
case IPT_TTL_DEC:
new_ttl = iph->ttl - info->ttl;
if (new_ttl < 0)
new_ttl = 0;
break;
default:
new_ttl = iph->ttl;
break;
}
if (new_ttl != iph->ttl) {
csum_replace2(&iph->check, htons(iph->ttl << 8),
htons(new_ttl << 8));
iph->ttl = new_ttl;
}
return XT_CONTINUE;
}
static unsigned int
hl_tg6(struct sk_buff *skb, const struct xt_target_param *par)
{
struct ipv6hdr *ip6h;
const struct ip6t_HL_info *info = par->targinfo;
int new_hl;
if (!skb_make_writable(skb, skb->len))
return NF_DROP;
ip6h = ipv6_hdr(skb);
switch (info->mode) {
case IP6T_HL_SET:
new_hl = info->hop_limit;
break;
case IP6T_HL_INC:
new_hl = ip6h->hop_limit + info->hop_limit;
if (new_hl > 255)
new_hl = 255;
break;
case IP6T_HL_DEC:
new_hl = ip6h->hop_limit - info->hop_limit;
if (new_hl < 0)
new_hl = 0;
break;
default:
new_hl = ip6h->hop_limit;
break;
}
ip6h->hop_limit = new_hl;
return XT_CONTINUE;
}
static bool ttl_tg_check(const struct xt_tgchk_param *par)
{
const struct ipt_TTL_info *info = par->targinfo;
if (info->mode > IPT_TTL_MAXMODE) {
printk(KERN_WARNING "ipt_TTL: invalid or unknown Mode %u\n",
info->mode);
return false;
}
if (info->mode != IPT_TTL_SET && info->ttl == 0)
return false;
return true;
}
static bool hl_tg6_check(const struct xt_tgchk_param *par)
{
const struct ip6t_HL_info *info = par->targinfo;
if (info->mode > IP6T_HL_MAXMODE) {
printk(KERN_WARNING "ip6t_HL: invalid or unknown Mode %u\n",
info->mode);
return false;
}
if (info->mode != IP6T_HL_SET && info->hop_limit == 0) {
printk(KERN_WARNING "ip6t_HL: increment/decrement doesn't "
"make sense with value 0\n");
return false;
}
return true;
}
static struct xt_target hl_tg_reg[] __read_mostly = {
{
.name = "TTL",
.revision = 0,
.family = NFPROTO_IPV4,
.target = ttl_tg,
.targetsize = sizeof(struct ipt_TTL_info),
.table = "mangle",
.checkentry = ttl_tg_check,
.me = THIS_MODULE,
},
{
.name = "HL",
.revision = 0,
.family = NFPROTO_IPV6,
.target = hl_tg6,
.targetsize = sizeof(struct ip6t_HL_info),
.table = "mangle",
.checkentry = hl_tg6_check,
.me = THIS_MODULE,
},
};
static int __init hl_tg_init(void)
{
return xt_register_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
}
static void __exit hl_tg_exit(void)
{
xt_unregister_targets(hl_tg_reg, ARRAY_SIZE(hl_tg_reg));
}
module_init(hl_tg_init);
module_exit(hl_tg_exit);
MODULE_ALIAS("ipt_TTL");
MODULE_ALIAS("ip6t_HL");

View File

@ -1,56 +0,0 @@
/*
* xt_MARK - Netfilter module to modify the NFMARK field of an skb
*
* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
* Copyright © CC Computer Consultants GmbH, 2007 - 2008
* Jan Engelhardt <jengelh@computergmbh.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/checksum.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_MARK.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
MODULE_DESCRIPTION("Xtables: packet mark modification");
MODULE_ALIAS("ipt_MARK");
MODULE_ALIAS("ip6t_MARK");
static unsigned int
mark_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_mark_tginfo2 *info = par->targinfo;
skb->mark = (skb->mark & ~info->mask) ^ info->mark;
return XT_CONTINUE;
}
static struct xt_target mark_tg_reg __read_mostly = {
.name = "MARK",
.revision = 2,
.family = NFPROTO_UNSPEC,
.target = mark_tg,
.targetsize = sizeof(struct xt_mark_tginfo2),
.me = THIS_MODULE,
};
static int __init mark_tg_init(void)
{
return xt_register_target(&mark_tg_reg);
}
static void __exit mark_tg_exit(void)
{
xt_unregister_target(&mark_tg_reg);
}
module_init(mark_tg_init);
module_exit(mark_tg_exit);

View File

@ -1,183 +0,0 @@
/*
* (C) 2007 Patrick McHardy <kaber@trash.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/gen_stats.h>
#include <linux/jhash.h>
#include <linux/rtnetlink.h>
#include <linux/random.h>
#include <net/gen_stats.h>
#include <net/netlink.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_RATEEST.h>
#include <net/netfilter/xt_rateest.h>
static DEFINE_MUTEX(xt_rateest_mutex);
#define RATEEST_HSIZE 16
static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly;
static unsigned int jhash_rnd __read_mostly;
static unsigned int xt_rateest_hash(const char *name)
{
return jhash(name, FIELD_SIZEOF(struct xt_rateest, name), jhash_rnd) &
(RATEEST_HSIZE - 1);
}
static void xt_rateest_hash_insert(struct xt_rateest *est)
{
unsigned int h;
h = xt_rateest_hash(est->name);
hlist_add_head(&est->list, &rateest_hash[h]);
}
struct xt_rateest *xt_rateest_lookup(const char *name)
{
struct xt_rateest *est;
struct hlist_node *n;
unsigned int h;
h = xt_rateest_hash(name);
mutex_lock(&xt_rateest_mutex);
hlist_for_each_entry(est, n, &rateest_hash[h], list) {
if (strcmp(est->name, name) == 0) {
est->refcnt++;
mutex_unlock(&xt_rateest_mutex);
return est;
}
}
mutex_unlock(&xt_rateest_mutex);
return NULL;
}
EXPORT_SYMBOL_GPL(xt_rateest_lookup);
void xt_rateest_put(struct xt_rateest *est)
{
mutex_lock(&xt_rateest_mutex);
if (--est->refcnt == 0) {
hlist_del(&est->list);
gen_kill_estimator(&est->bstats, &est->rstats);
kfree(est);
}
mutex_unlock(&xt_rateest_mutex);
}
EXPORT_SYMBOL_GPL(xt_rateest_put);
static unsigned int
xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_rateest_target_info *info = par->targinfo;
struct gnet_stats_basic_packed *stats = &info->est->bstats;
spin_lock_bh(&info->est->lock);
stats->bytes += skb->len;
stats->packets++;
spin_unlock_bh(&info->est->lock);
return XT_CONTINUE;
}
static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
{
struct xt_rateest_target_info *info = par->targinfo;
struct xt_rateest *est;
struct {
struct nlattr opt;
struct gnet_estimator est;
} cfg;
est = xt_rateest_lookup(info->name);
if (est) {
/*
* If estimator parameters are specified, they must match the
* existing estimator.
*/
if ((!info->interval && !info->ewma_log) ||
(info->interval != est->params.interval ||
info->ewma_log != est->params.ewma_log)) {
xt_rateest_put(est);
return false;
}
info->est = est;
return true;
}
est = kzalloc(sizeof(*est), GFP_KERNEL);
if (!est)
goto err1;
strlcpy(est->name, info->name, sizeof(est->name));
spin_lock_init(&est->lock);
est->refcnt = 1;
est->params.interval = info->interval;
est->params.ewma_log = info->ewma_log;
cfg.opt.nla_len = nla_attr_size(sizeof(cfg.est));
cfg.opt.nla_type = TCA_STATS_RATE_EST;
cfg.est.interval = info->interval;
cfg.est.ewma_log = info->ewma_log;
if (gen_new_estimator(&est->bstats, &est->rstats, &est->lock,
&cfg.opt) < 0)
goto err2;
info->est = est;
xt_rateest_hash_insert(est);
return true;
err2:
kfree(est);
err1:
return false;
}
static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
{
struct xt_rateest_target_info *info = par->targinfo;
xt_rateest_put(info->est);
}
static struct xt_target xt_rateest_tg_reg __read_mostly = {
.name = "RATEEST",
.revision = 0,
.family = NFPROTO_UNSPEC,
.target = xt_rateest_tg,
.checkentry = xt_rateest_tg_checkentry,
.destroy = xt_rateest_tg_destroy,
.targetsize = sizeof(struct xt_rateest_target_info),
.me = THIS_MODULE,
};
static int __init xt_rateest_tg_init(void)
{
unsigned int i;
for (i = 0; i < ARRAY_SIZE(rateest_hash); i++)
INIT_HLIST_HEAD(&rateest_hash[i]);
get_random_bytes(&jhash_rnd, sizeof(jhash_rnd));
return xt_register_target(&xt_rateest_tg_reg);
}
static void __exit xt_rateest_tg_fini(void)
{
xt_unregister_target(&xt_rateest_tg_reg);
}
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Xtables: packet rate estimator");
MODULE_ALIAS("ipt_RATEEST");
MODULE_ALIAS("ip6t_RATEEST");
module_init(xt_rateest_tg_init);
module_exit(xt_rateest_tg_fini);

View File

@ -1,7 +1,7 @@
/*
* This is a module which is used for setting the MSS option in TCP packets.
*
* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
/* Kernel module to match TCP MSS values. */
/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
* Portions (C) 2005 by Harald Welte <laforge@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -10,305 +10,101 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <linux/ipv6.h>
#include <linux/tcp.h>
#include <net/dst.h>
#include <net/flow.h>
#include <net/ipv6.h>
#include <net/route.h>
#include <net/tcp.h>
#include <linux/netfilter/xt_tcpmss.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_tcpudp.h>
#include <linux/netfilter/xt_TCPMSS.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
MODULE_DESCRIPTION("Xtables: TCP Maximum Segment Size (MSS) adjustment");
MODULE_ALIAS("ipt_TCPMSS");
MODULE_ALIAS("ip6t_TCPMSS");
MODULE_DESCRIPTION("Xtables: TCP MSS match");
MODULE_ALIAS("ipt_tcpmss");
MODULE_ALIAS("ip6t_tcpmss");
static inline unsigned int
optlen(const u_int8_t *opt, unsigned int offset)
static bool
tcpmss_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
/* Beware zero-length options: make finite progress */
if (opt[offset] <= TCPOPT_NOP || opt[offset+1] == 0)
return 1;
else
return opt[offset+1];
}
const struct xt_tcpmss_match_info *info = par->matchinfo;
const struct tcphdr *th;
struct tcphdr _tcph;
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
const u_int8_t *op;
u8 _opt[15 * 4 - sizeof(_tcph)];
unsigned int i, optlen;
static int
tcpmss_mangle_packet(struct sk_buff *skb,
const struct xt_tcpmss_info *info,
unsigned int in_mtu,
unsigned int tcphoff,
unsigned int minlen)
{
struct tcphdr *tcph;
unsigned int tcplen, i;
__be16 oldval;
u16 newmss;
u8 *opt;
/* If we don't have the whole header, drop packet. */
th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
if (th == NULL)
goto dropit;
if (!skb_make_writable(skb, skb->len))
return -1;
/* Malformed. */
if (th->doff*4 < sizeof(*th))
goto dropit;
tcplen = skb->len - tcphoff;
tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
optlen = th->doff*4 - sizeof(*th);
if (!optlen)
goto out;
/* Since it passed flags test in tcp match, we know it is is
not a fragment, and has data >= tcp header length. SYN
packets should not contain data: if they did, then we risk
running over MTU, sending Frag Needed and breaking things
badly. --RR */
if (tcplen != tcph->doff*4) {
if (net_ratelimit())
printk(KERN_ERR "xt_TCPMSS: bad length (%u bytes)\n",
skb->len);
return -1;
}
/* Truncated options. */
op = skb_header_pointer(skb, par->thoff + sizeof(*th), optlen, _opt);
if (op == NULL)
goto dropit;
if (info->mss == XT_TCPMSS_CLAMP_PMTU) {
if (dst_mtu(skb_dst(skb)) <= minlen) {
if (net_ratelimit())
printk(KERN_ERR "xt_TCPMSS: "
"unknown or invalid path-MTU (%u)\n",
dst_mtu(skb_dst(skb)));
return -1;
}
if (in_mtu <= minlen) {
if (net_ratelimit())
printk(KERN_ERR "xt_TCPMSS: unknown or "
"invalid path-MTU (%u)\n", in_mtu);
return -1;
}
newmss = min(dst_mtu(skb_dst(skb)), in_mtu) - minlen;
} else
newmss = info->mss;
opt = (u_int8_t *)tcph;
for (i = sizeof(struct tcphdr); i < tcph->doff*4; i += optlen(opt, i)) {
if (opt[i] == TCPOPT_MSS && tcph->doff*4 - i >= TCPOLEN_MSS &&
opt[i+1] == TCPOLEN_MSS) {
u_int16_t oldmss;
oldmss = (opt[i+2] << 8) | opt[i+3];
/* Never increase MSS, even when setting it, as
* doing so results in problems for hosts that rely
* on MSS being set correctly.
*/
if (oldmss <= newmss)
return 0;
opt[i+2] = (newmss & 0xff00) >> 8;
opt[i+3] = newmss & 0x00ff;
inet_proto_csum_replace2(&tcph->check, skb,
htons(oldmss), htons(newmss),
0);
return 0;
for (i = 0; i < optlen; ) {
if (op[i] == TCPOPT_MSS
&& (optlen - i) >= TCPOLEN_MSS
&& op[i+1] == TCPOLEN_MSS) {
u_int16_t mssval;
mssval = (op[i+2] << 8) | op[i+3];
return (mssval >= info->mss_min &&
mssval <= info->mss_max) ^ info->invert;
}
if (op[i] < 2)
i++;
else
i += op[i+1] ? : 1;
}
out:
return info->invert;
/*
* MSS Option not found ?! add it..
*/
if (skb_tailroom(skb) < TCPOLEN_MSS) {
if (pskb_expand_head(skb, 0,
TCPOLEN_MSS - skb_tailroom(skb),
GFP_ATOMIC))
return -1;
tcph = (struct tcphdr *)(skb_network_header(skb) + tcphoff);
}
skb_put(skb, TCPOLEN_MSS);
opt = (u_int8_t *)tcph + sizeof(struct tcphdr);
memmove(opt + TCPOLEN_MSS, opt, tcplen - sizeof(struct tcphdr));
inet_proto_csum_replace2(&tcph->check, skb,
htons(tcplen), htons(tcplen + TCPOLEN_MSS), 1);
opt[0] = TCPOPT_MSS;
opt[1] = TCPOLEN_MSS;
opt[2] = (newmss & 0xff00) >> 8;
opt[3] = newmss & 0x00ff;
inet_proto_csum_replace4(&tcph->check, skb, 0, *((__be32 *)opt), 0);
oldval = ((__be16 *)tcph)[6];
tcph->doff += TCPOLEN_MSS/4;
inet_proto_csum_replace2(&tcph->check, skb,
oldval, ((__be16 *)tcph)[6], 0);
return TCPOLEN_MSS;
}
static u_int32_t tcpmss_reverse_mtu(const struct sk_buff *skb,
unsigned int family)
{
struct flowi fl = {};
const struct nf_afinfo *ai;
struct rtable *rt = NULL;
u_int32_t mtu = ~0U;
if (family == PF_INET)
fl.fl4_dst = ip_hdr(skb)->saddr;
else
fl.fl6_dst = ipv6_hdr(skb)->saddr;
rcu_read_lock();
ai = nf_get_afinfo(family);
if (ai != NULL)
ai->route((struct dst_entry **)&rt, &fl);
rcu_read_unlock();
if (rt != NULL) {
mtu = dst_mtu(&rt->u.dst);
dst_release(&rt->u.dst);
}
return mtu;
}
static unsigned int
tcpmss_tg4(struct sk_buff *skb, const struct xt_target_param *par)
{
struct iphdr *iph = ip_hdr(skb);
__be16 newlen;
int ret;
ret = tcpmss_mangle_packet(skb, par->targinfo,
tcpmss_reverse_mtu(skb, PF_INET),
iph->ihl * 4,
sizeof(*iph) + sizeof(struct tcphdr));
if (ret < 0)
return NF_DROP;
if (ret > 0) {
iph = ip_hdr(skb);
newlen = htons(ntohs(iph->tot_len) + ret);
csum_replace2(&iph->check, iph->tot_len, newlen);
iph->tot_len = newlen;
}
return XT_CONTINUE;
}
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
static unsigned int
tcpmss_tg6(struct sk_buff *skb, const struct xt_target_param *par)
{
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
u8 nexthdr;
int tcphoff;
int ret;
nexthdr = ipv6h->nexthdr;
tcphoff = ipv6_skip_exthdr(skb, sizeof(*ipv6h), &nexthdr);
if (tcphoff < 0)
return NF_DROP;
ret = tcpmss_mangle_packet(skb, par->targinfo,
tcpmss_reverse_mtu(skb, PF_INET6),
tcphoff,
sizeof(*ipv6h) + sizeof(struct tcphdr));
if (ret < 0)
return NF_DROP;
if (ret > 0) {
ipv6h = ipv6_hdr(skb);
ipv6h->payload_len = htons(ntohs(ipv6h->payload_len) + ret);
}
return XT_CONTINUE;
}
#endif
#define TH_SYN 0x02
/* Must specify -p tcp --syn */
static inline bool find_syn_match(const struct xt_entry_match *m)
{
const struct xt_tcp *tcpinfo = (const struct xt_tcp *)m->data;
if (strcmp(m->u.kernel.match->name, "tcp") == 0 &&
tcpinfo->flg_cmp & TH_SYN &&
!(tcpinfo->invflags & XT_TCP_INV_FLAGS))
return true;
dropit:
*par->hotdrop = true;
return false;
}
static bool tcpmss_tg4_check(const struct xt_tgchk_param *par)
{
const struct xt_tcpmss_info *info = par->targinfo;
const struct ipt_entry *e = par->entryinfo;
if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
(par->hook_mask & ~((1 << NF_INET_FORWARD) |
(1 << NF_INET_LOCAL_OUT) |
(1 << NF_INET_POST_ROUTING))) != 0) {
printk("xt_TCPMSS: path-MTU clamping only supported in "
"FORWARD, OUTPUT and POSTROUTING hooks\n");
return false;
}
if (IPT_MATCH_ITERATE(e, find_syn_match))
return true;
printk("xt_TCPMSS: Only works on TCP SYN packets\n");
return false;
}
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
static bool tcpmss_tg6_check(const struct xt_tgchk_param *par)
{
const struct xt_tcpmss_info *info = par->targinfo;
const struct ip6t_entry *e = par->entryinfo;
if (info->mss == XT_TCPMSS_CLAMP_PMTU &&
(par->hook_mask & ~((1 << NF_INET_FORWARD) |
(1 << NF_INET_LOCAL_OUT) |
(1 << NF_INET_POST_ROUTING))) != 0) {
printk("xt_TCPMSS: path-MTU clamping only supported in "
"FORWARD, OUTPUT and POSTROUTING hooks\n");
return false;
}
if (IP6T_MATCH_ITERATE(e, find_syn_match))
return true;
printk("xt_TCPMSS: Only works on TCP SYN packets\n");
return false;
}
#endif
static struct xt_target tcpmss_tg_reg[] __read_mostly = {
static struct xt_match tcpmss_mt_reg[] __read_mostly = {
{
.name = "tcpmss",
.family = NFPROTO_IPV4,
.name = "TCPMSS",
.checkentry = tcpmss_tg4_check,
.target = tcpmss_tg4,
.targetsize = sizeof(struct xt_tcpmss_info),
.match = tcpmss_mt,
.matchsize = sizeof(struct xt_tcpmss_match_info),
.proto = IPPROTO_TCP,
.me = THIS_MODULE,
},
#if defined(CONFIG_IP6_NF_IPTABLES) || defined(CONFIG_IP6_NF_IPTABLES_MODULE)
{
.name = "tcpmss",
.family = NFPROTO_IPV6,
.name = "TCPMSS",
.checkentry = tcpmss_tg6_check,
.target = tcpmss_tg6,
.targetsize = sizeof(struct xt_tcpmss_info),
.match = tcpmss_mt,
.matchsize = sizeof(struct xt_tcpmss_match_info),
.proto = IPPROTO_TCP,
.me = THIS_MODULE,
},
#endif
};
static int __init tcpmss_tg_init(void)
static int __init tcpmss_mt_init(void)
{
return xt_register_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
return xt_register_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
}
static void __exit tcpmss_tg_exit(void)
static void __exit tcpmss_mt_exit(void)
{
xt_unregister_targets(tcpmss_tg_reg, ARRAY_SIZE(tcpmss_tg_reg));
xt_unregister_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
}
module_init(tcpmss_tg_init);
module_exit(tcpmss_tg_exit);
module_init(tcpmss_mt_init);
module_exit(tcpmss_mt_exit);

View File

@ -1,5 +1,5 @@
/*
* xt_connmark - Netfilter module to match connection mark values
* xt_CONNMARK - Netfilter module to modify the connection mark values
*
* Copyright (C) 2002,2004 MARA Systems AB <http://www.marasystems.com>
* by Henrik Nordstrom <hno@marasystems.com>
@ -20,34 +20,60 @@
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <net/netfilter/nf_conntrack.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_connmark.h>
#include <linux/ip.h>
#include <net/checksum.h>
MODULE_AUTHOR("Henrik Nordstrom <hno@marasystems.com>");
MODULE_DESCRIPTION("Xtables: connection mark match");
MODULE_DESCRIPTION("Xtables: connection mark modification");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_connmark");
MODULE_ALIAS("ip6t_connmark");
MODULE_ALIAS("ipt_CONNMARK");
MODULE_ALIAS("ip6t_CONNMARK");
static bool
connmark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_CONNMARK.h>
#include <net/netfilter/nf_conntrack_ecache.h>
static unsigned int
connmark_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_connmark_mtinfo1 *info = par->matchinfo;
const struct xt_connmark_tginfo1 *info = par->targinfo;
enum ip_conntrack_info ctinfo;
const struct nf_conn *ct;
struct nf_conn *ct;
u_int32_t newmark;
ct = nf_ct_get(skb, &ctinfo);
if (ct == NULL)
return false;
return XT_CONTINUE;
return ((ct->mark & info->mask) == info->mark) ^ info->invert;
switch (info->mode) {
case XT_CONNMARK_SET:
newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
if (ct->mark != newmark) {
ct->mark = newmark;
nf_conntrack_event_cache(IPCT_MARK, ct);
}
break;
case XT_CONNMARK_SAVE:
newmark = (ct->mark & ~info->ctmask) ^
(skb->mark & info->nfmask);
if (ct->mark != newmark) {
ct->mark = newmark;
nf_conntrack_event_cache(IPCT_MARK, ct);
}
break;
case XT_CONNMARK_RESTORE:
newmark = (skb->mark & ~info->nfmask) ^
(ct->mark & info->ctmask);
skb->mark = newmark;
break;
}
return XT_CONTINUE;
}
static bool connmark_mt_check(const struct xt_mtchk_param *par)
static bool connmark_tg_check(const struct xt_tgchk_param *par)
{
if (nf_ct_l3proto_try_module_get(par->family) < 0) {
printk(KERN_WARNING "cannot load conntrack support for "
@ -57,31 +83,31 @@ static bool connmark_mt_check(const struct xt_mtchk_param *par)
return true;
}
static void connmark_mt_destroy(const struct xt_mtdtor_param *par)
static void connmark_tg_destroy(const struct xt_tgdtor_param *par)
{
nf_ct_l3proto_module_put(par->family);
}
static struct xt_match connmark_mt_reg __read_mostly = {
.name = "connmark",
static struct xt_target connmark_tg_reg __read_mostly = {
.name = "CONNMARK",
.revision = 1,
.family = NFPROTO_UNSPEC,
.checkentry = connmark_mt_check,
.match = connmark_mt,
.matchsize = sizeof(struct xt_connmark_mtinfo1),
.destroy = connmark_mt_destroy,
.checkentry = connmark_tg_check,
.target = connmark_tg,
.targetsize = sizeof(struct xt_connmark_tginfo1),
.destroy = connmark_tg_destroy,
.me = THIS_MODULE,
};
static int __init connmark_mt_init(void)
static int __init connmark_tg_init(void)
{
return xt_register_match(&connmark_mt_reg);
return xt_register_target(&connmark_tg_reg);
}
static void __exit connmark_mt_exit(void)
static void __exit connmark_tg_exit(void)
{
xt_unregister_match(&connmark_mt_reg);
xt_unregister_target(&connmark_tg_reg);
}
module_init(connmark_mt_init);
module_exit(connmark_mt_exit);
module_init(connmark_tg_init);
module_exit(connmark_tg_exit);

View File

@ -1,11 +1,14 @@
/* IP tables module for matching the value of the IPv4/IPv6 DSCP field
/* x_tables module for setting the IPv4/IPv6 DSCP field, Version 1.8
*
* (C) 2002 by Harald Welte <laforge@netfilter.org>
* based on ipt_FTOS.c (C) 2000 by Matthew G. Marsh <mgm@paktronix.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
*
* See RFC2474 for a description of the DSCP field within the IP Header.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
@ -14,102 +17,148 @@
#include <net/dsfield.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_dscp.h>
#include <linux/netfilter/xt_DSCP.h>
MODULE_AUTHOR("Harald Welte <laforge@netfilter.org>");
MODULE_DESCRIPTION("Xtables: DSCP/TOS field match");
MODULE_DESCRIPTION("Xtables: DSCP/TOS field modification");
MODULE_LICENSE("GPL");
MODULE_ALIAS("ipt_dscp");
MODULE_ALIAS("ip6t_dscp");
MODULE_ALIAS("ipt_tos");
MODULE_ALIAS("ip6t_tos");
MODULE_ALIAS("ipt_DSCP");
MODULE_ALIAS("ip6t_DSCP");
MODULE_ALIAS("ipt_TOS");
MODULE_ALIAS("ip6t_TOS");
static bool
dscp_mt(const struct sk_buff *skb, const struct xt_match_param *par)
static unsigned int
dscp_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_dscp_info *info = par->matchinfo;
const struct xt_DSCP_info *dinfo = par->targinfo;
u_int8_t dscp = ipv4_get_dsfield(ip_hdr(skb)) >> XT_DSCP_SHIFT;
return (dscp == info->dscp) ^ !!info->invert;
if (dscp != dinfo->dscp) {
if (!skb_make_writable(skb, sizeof(struct iphdr)))
return NF_DROP;
ipv4_change_dsfield(ip_hdr(skb), (__u8)(~XT_DSCP_MASK),
dinfo->dscp << XT_DSCP_SHIFT);
}
return XT_CONTINUE;
}
static bool
dscp_mt6(const struct sk_buff *skb, const struct xt_match_param *par)
static unsigned int
dscp_tg6(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_dscp_info *info = par->matchinfo;
const struct xt_DSCP_info *dinfo = par->targinfo;
u_int8_t dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> XT_DSCP_SHIFT;
return (dscp == info->dscp) ^ !!info->invert;
if (dscp != dinfo->dscp) {
if (!skb_make_writable(skb, sizeof(struct ipv6hdr)))
return NF_DROP;
ipv6_change_dsfield(ipv6_hdr(skb), (__u8)(~XT_DSCP_MASK),
dinfo->dscp << XT_DSCP_SHIFT);
}
return XT_CONTINUE;
}
static bool dscp_mt_check(const struct xt_mtchk_param *par)
static bool dscp_tg_check(const struct xt_tgchk_param *par)
{
const struct xt_dscp_info *info = par->matchinfo;
const struct xt_DSCP_info *info = par->targinfo;
if (info->dscp > XT_DSCP_MAX) {
printk(KERN_ERR "xt_dscp: dscp %x out of range\n", info->dscp);
printk(KERN_WARNING "DSCP: dscp %x out of range\n", info->dscp);
return false;
}
return true;
}
static bool tos_mt(const struct sk_buff *skb, const struct xt_match_param *par)
static unsigned int
tos_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_tos_match_info *info = par->matchinfo;
const struct xt_tos_target_info *info = par->targinfo;
struct iphdr *iph = ip_hdr(skb);
u_int8_t orig, nv;
if (par->match->family == NFPROTO_IPV4)
return ((ip_hdr(skb)->tos & info->tos_mask) ==
info->tos_value) ^ !!info->invert;
else
return ((ipv6_get_dsfield(ipv6_hdr(skb)) & info->tos_mask) ==
info->tos_value) ^ !!info->invert;
orig = ipv4_get_dsfield(iph);
nv = (orig & ~info->tos_mask) ^ info->tos_value;
if (orig != nv) {
if (!skb_make_writable(skb, sizeof(struct iphdr)))
return NF_DROP;
iph = ip_hdr(skb);
ipv4_change_dsfield(iph, 0, nv);
}
return XT_CONTINUE;
}
static struct xt_match dscp_mt_reg[] __read_mostly = {
static unsigned int
tos_tg6(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_tos_target_info *info = par->targinfo;
struct ipv6hdr *iph = ipv6_hdr(skb);
u_int8_t orig, nv;
orig = ipv6_get_dsfield(iph);
nv = (orig & info->tos_mask) ^ info->tos_value;
if (orig != nv) {
if (!skb_make_writable(skb, sizeof(struct iphdr)))
return NF_DROP;
iph = ipv6_hdr(skb);
ipv6_change_dsfield(iph, 0, nv);
}
return XT_CONTINUE;
}
static struct xt_target dscp_tg_reg[] __read_mostly = {
{
.name = "dscp",
.name = "DSCP",
.family = NFPROTO_IPV4,
.checkentry = dscp_mt_check,
.match = dscp_mt,
.matchsize = sizeof(struct xt_dscp_info),
.checkentry = dscp_tg_check,
.target = dscp_tg,
.targetsize = sizeof(struct xt_DSCP_info),
.table = "mangle",
.me = THIS_MODULE,
},
{
.name = "dscp",
.name = "DSCP",
.family = NFPROTO_IPV6,
.checkentry = dscp_mt_check,
.match = dscp_mt6,
.matchsize = sizeof(struct xt_dscp_info),
.checkentry = dscp_tg_check,
.target = dscp_tg6,
.targetsize = sizeof(struct xt_DSCP_info),
.table = "mangle",
.me = THIS_MODULE,
},
{
.name = "tos",
.name = "TOS",
.revision = 1,
.family = NFPROTO_IPV4,
.match = tos_mt,
.matchsize = sizeof(struct xt_tos_match_info),
.table = "mangle",
.target = tos_tg,
.targetsize = sizeof(struct xt_tos_target_info),
.me = THIS_MODULE,
},
{
.name = "tos",
.name = "TOS",
.revision = 1,
.family = NFPROTO_IPV6,
.match = tos_mt,
.matchsize = sizeof(struct xt_tos_match_info),
.table = "mangle",
.target = tos_tg6,
.targetsize = sizeof(struct xt_tos_target_info),
.me = THIS_MODULE,
},
};
static int __init dscp_mt_init(void)
static int __init dscp_tg_init(void)
{
return xt_register_matches(dscp_mt_reg, ARRAY_SIZE(dscp_mt_reg));
return xt_register_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg));
}
static void __exit dscp_mt_exit(void)
static void __exit dscp_tg_exit(void)
{
xt_unregister_matches(dscp_mt_reg, ARRAY_SIZE(dscp_mt_reg));
xt_unregister_targets(dscp_tg_reg, ARRAY_SIZE(dscp_tg_reg));
}
module_init(dscp_mt_init);
module_exit(dscp_mt_exit);
module_init(dscp_tg_init);
module_exit(dscp_tg_exit);

View File

@ -16,8 +16,8 @@
#include <linux/skbuff.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ipt_ttl.h>
#include <linux/netfilter_ipv6/ip6t_hl.h>
#include <linux/netfilter_ipv4/ipt_TTL.h>
#include <linux/netfilter_ipv6/ip6t_HL.h>
MODULE_AUTHOR("Maciej Soltysiak <solt@dns.toxicfilms.tv>");
MODULE_DESCRIPTION("Xtables: Hoplimit/TTL field match");

View File

@ -1,9 +1,9 @@
/*
* xt_mark - Netfilter module to match NFMARK value
* xt_MARK - Netfilter module to modify the NFMARK field of an skb
*
* (C) 1999-2001 Marc Boucher <marc@mbsi.ca>
* Copyright © CC Computer Consultants GmbH, 2007 - 2008
* Jan Engelhardt <jengelh@medozas.de>
* Jan Engelhardt <jengelh@computergmbh.de>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@ -12,42 +12,45 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/checksum.h>
#include <linux/netfilter/xt_mark.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_mark.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
MODULE_DESCRIPTION("Xtables: packet mark match");
MODULE_ALIAS("ipt_mark");
MODULE_ALIAS("ip6t_mark");
MODULE_DESCRIPTION("Xtables: packet mark modification");
MODULE_ALIAS("ipt_MARK");
MODULE_ALIAS("ip6t_MARK");
static bool
mark_mt(const struct sk_buff *skb, const struct xt_match_param *par)
static unsigned int
mark_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_mark_mtinfo1 *info = par->matchinfo;
const struct xt_mark_tginfo2 *info = par->targinfo;
return ((skb->mark & info->mask) == info->mark) ^ info->invert;
skb->mark = (skb->mark & ~info->mask) ^ info->mark;
return XT_CONTINUE;
}
static struct xt_match mark_mt_reg __read_mostly = {
.name = "mark",
.revision = 1,
static struct xt_target mark_tg_reg __read_mostly = {
.name = "MARK",
.revision = 2,
.family = NFPROTO_UNSPEC,
.match = mark_mt,
.matchsize = sizeof(struct xt_mark_mtinfo1),
.target = mark_tg,
.targetsize = sizeof(struct xt_mark_tginfo2),
.me = THIS_MODULE,
};
static int __init mark_mt_init(void)
static int __init mark_tg_init(void)
{
return xt_register_match(&mark_mt_reg);
return xt_register_target(&mark_tg_reg);
}
static void __exit mark_mt_exit(void)
static void __exit mark_tg_exit(void)
{
xt_unregister_match(&mark_mt_reg);
xt_unregister_target(&mark_tg_reg);
}
module_init(mark_mt_init);
module_exit(mark_mt_exit);
module_init(mark_tg_init);
module_exit(mark_tg_exit);

View File

@ -8,149 +8,176 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/gen_stats.h>
#include <linux/jhash.h>
#include <linux/rtnetlink.h>
#include <linux/random.h>
#include <net/gen_stats.h>
#include <net/netlink.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter/xt_rateest.h>
#include <linux/netfilter/xt_RATEEST.h>
#include <net/netfilter/xt_rateest.h>
static DEFINE_MUTEX(xt_rateest_mutex);
static bool
xt_rateest_mt(const struct sk_buff *skb, const struct xt_match_param *par)
#define RATEEST_HSIZE 16
static struct hlist_head rateest_hash[RATEEST_HSIZE] __read_mostly;
static unsigned int jhash_rnd __read_mostly;
static unsigned int xt_rateest_hash(const char *name)
{
const struct xt_rateest_match_info *info = par->matchinfo;
struct gnet_stats_rate_est *r;
u_int32_t bps1, bps2, pps1, pps2;
bool ret = true;
spin_lock_bh(&info->est1->lock);
r = &info->est1->rstats;
if (info->flags & XT_RATEEST_MATCH_DELTA) {
bps1 = info->bps1 >= r->bps ? info->bps1 - r->bps : 0;
pps1 = info->pps1 >= r->pps ? info->pps1 - r->pps : 0;
} else {
bps1 = r->bps;
pps1 = r->pps;
}
spin_unlock_bh(&info->est1->lock);
if (info->flags & XT_RATEEST_MATCH_ABS) {
bps2 = info->bps2;
pps2 = info->pps2;
} else {
spin_lock_bh(&info->est2->lock);
r = &info->est2->rstats;
if (info->flags & XT_RATEEST_MATCH_DELTA) {
bps2 = info->bps2 >= r->bps ? info->bps2 - r->bps : 0;
pps2 = info->pps2 >= r->pps ? info->pps2 - r->pps : 0;
} else {
bps2 = r->bps;
pps2 = r->pps;
}
spin_unlock_bh(&info->est2->lock);
}
switch (info->mode) {
case XT_RATEEST_MATCH_LT:
if (info->flags & XT_RATEEST_MATCH_BPS)
ret &= bps1 < bps2;
if (info->flags & XT_RATEEST_MATCH_PPS)
ret &= pps1 < pps2;
break;
case XT_RATEEST_MATCH_GT:
if (info->flags & XT_RATEEST_MATCH_BPS)
ret &= bps1 > bps2;
if (info->flags & XT_RATEEST_MATCH_PPS)
ret &= pps1 > pps2;
break;
case XT_RATEEST_MATCH_EQ:
if (info->flags & XT_RATEEST_MATCH_BPS)
ret &= bps1 == bps2;
if (info->flags & XT_RATEEST_MATCH_PPS)
ret &= pps1 == pps2;
break;
}
ret ^= info->flags & XT_RATEEST_MATCH_INVERT ? true : false;
return ret;
return jhash(name, FIELD_SIZEOF(struct xt_rateest, name), jhash_rnd) &
(RATEEST_HSIZE - 1);
}
static bool xt_rateest_mt_checkentry(const struct xt_mtchk_param *par)
static void xt_rateest_hash_insert(struct xt_rateest *est)
{
struct xt_rateest_match_info *info = par->matchinfo;
struct xt_rateest *est1, *est2;
unsigned int h;
if (hweight32(info->flags & (XT_RATEEST_MATCH_ABS |
XT_RATEEST_MATCH_REL)) != 1)
goto err1;
h = xt_rateest_hash(est->name);
hlist_add_head(&est->list, &rateest_hash[h]);
}
if (!(info->flags & (XT_RATEEST_MATCH_BPS | XT_RATEEST_MATCH_PPS)))
goto err1;
struct xt_rateest *xt_rateest_lookup(const char *name)
{
struct xt_rateest *est;
struct hlist_node *n;
unsigned int h;
switch (info->mode) {
case XT_RATEEST_MATCH_EQ:
case XT_RATEEST_MATCH_LT:
case XT_RATEEST_MATCH_GT:
break;
default:
goto err1;
h = xt_rateest_hash(name);
mutex_lock(&xt_rateest_mutex);
hlist_for_each_entry(est, n, &rateest_hash[h], list) {
if (strcmp(est->name, name) == 0) {
est->refcnt++;
mutex_unlock(&xt_rateest_mutex);
return est;
}
}
mutex_unlock(&xt_rateest_mutex);
return NULL;
}
EXPORT_SYMBOL_GPL(xt_rateest_lookup);
void xt_rateest_put(struct xt_rateest *est)
{
mutex_lock(&xt_rateest_mutex);
if (--est->refcnt == 0) {
hlist_del(&est->list);
gen_kill_estimator(&est->bstats, &est->rstats);
kfree(est);
}
mutex_unlock(&xt_rateest_mutex);
}
EXPORT_SYMBOL_GPL(xt_rateest_put);
static unsigned int
xt_rateest_tg(struct sk_buff *skb, const struct xt_target_param *par)
{
const struct xt_rateest_target_info *info = par->targinfo;
struct gnet_stats_basic_packed *stats = &info->est->bstats;
spin_lock_bh(&info->est->lock);
stats->bytes += skb->len;
stats->packets++;
spin_unlock_bh(&info->est->lock);
return XT_CONTINUE;
}
static bool xt_rateest_tg_checkentry(const struct xt_tgchk_param *par)
{
struct xt_rateest_target_info *info = par->targinfo;
struct xt_rateest *est;
struct {
struct nlattr opt;
struct gnet_estimator est;
} cfg;
est = xt_rateest_lookup(info->name);
if (est) {
/*
* If estimator parameters are specified, they must match the
* existing estimator.
*/
if ((!info->interval && !info->ewma_log) ||
(info->interval != est->params.interval ||
info->ewma_log != est->params.ewma_log)) {
xt_rateest_put(est);
return false;
}
info->est = est;
return true;
}
est1 = xt_rateest_lookup(info->name1);
if (!est1)
est = kzalloc(sizeof(*est), GFP_KERNEL);
if (!est)
goto err1;
if (info->flags & XT_RATEEST_MATCH_REL) {
est2 = xt_rateest_lookup(info->name2);
if (!est2)
goto err2;
} else
est2 = NULL;
strlcpy(est->name, info->name, sizeof(est->name));
spin_lock_init(&est->lock);
est->refcnt = 1;
est->params.interval = info->interval;
est->params.ewma_log = info->ewma_log;
cfg.opt.nla_len = nla_attr_size(sizeof(cfg.est));
cfg.opt.nla_type = TCA_STATS_RATE_EST;
cfg.est.interval = info->interval;
cfg.est.ewma_log = info->ewma_log;
if (gen_new_estimator(&est->bstats, &est->rstats, &est->lock,
&cfg.opt) < 0)
goto err2;
info->est = est;
xt_rateest_hash_insert(est);
info->est1 = est1;
info->est2 = est2;
return true;
err2:
xt_rateest_put(est1);
kfree(est);
err1:
return false;
}
static void xt_rateest_mt_destroy(const struct xt_mtdtor_param *par)
static void xt_rateest_tg_destroy(const struct xt_tgdtor_param *par)
{
struct xt_rateest_match_info *info = par->matchinfo;
struct xt_rateest_target_info *info = par->targinfo;
xt_rateest_put(info->est1);
if (info->est2)
xt_rateest_put(info->est2);
xt_rateest_put(info->est);
}
static struct xt_match xt_rateest_mt_reg __read_mostly = {
.name = "rateest",
static struct xt_target xt_rateest_tg_reg __read_mostly = {
.name = "RATEEST",
.revision = 0,
.family = NFPROTO_UNSPEC,
.match = xt_rateest_mt,
.checkentry = xt_rateest_mt_checkentry,
.destroy = xt_rateest_mt_destroy,
.matchsize = sizeof(struct xt_rateest_match_info),
.target = xt_rateest_tg,
.checkentry = xt_rateest_tg_checkentry,
.destroy = xt_rateest_tg_destroy,
.targetsize = sizeof(struct xt_rateest_target_info),
.me = THIS_MODULE,
};
static int __init xt_rateest_mt_init(void)
static int __init xt_rateest_tg_init(void)
{
return xt_register_match(&xt_rateest_mt_reg);
unsigned int i;
for (i = 0; i < ARRAY_SIZE(rateest_hash); i++)
INIT_HLIST_HEAD(&rateest_hash[i]);
get_random_bytes(&jhash_rnd, sizeof(jhash_rnd));
return xt_register_target(&xt_rateest_tg_reg);
}
static void __exit xt_rateest_mt_fini(void)
static void __exit xt_rateest_tg_fini(void)
{
xt_unregister_match(&xt_rateest_mt_reg);
xt_unregister_target(&xt_rateest_tg_reg);
}
MODULE_AUTHOR("Patrick McHardy <kaber@trash.net>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("xtables rate estimator match");
MODULE_ALIAS("ipt_rateest");
MODULE_ALIAS("ip6t_rateest");
module_init(xt_rateest_mt_init);
module_exit(xt_rateest_mt_fini);
MODULE_DESCRIPTION("Xtables: packet rate estimator");
MODULE_ALIAS("ipt_RATEEST");
MODULE_ALIAS("ip6t_RATEEST");
module_init(xt_rateest_tg_init);
module_exit(xt_rateest_tg_fini);

View File

@ -1,110 +0,0 @@
/* Kernel module to match TCP MSS values. */
/* Copyright (C) 2000 Marc Boucher <marc@mbsi.ca>
* Portions (C) 2005 by Harald Welte <laforge@netfilter.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/skbuff.h>
#include <net/tcp.h>
#include <linux/netfilter/xt_tcpmss.h>
#include <linux/netfilter/x_tables.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv6/ip6_tables.h>
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Marc Boucher <marc@mbsi.ca>");
MODULE_DESCRIPTION("Xtables: TCP MSS match");
MODULE_ALIAS("ipt_tcpmss");
MODULE_ALIAS("ip6t_tcpmss");
static bool
tcpmss_mt(const struct sk_buff *skb, const struct xt_match_param *par)
{
const struct xt_tcpmss_match_info *info = par->matchinfo;
const struct tcphdr *th;
struct tcphdr _tcph;
/* tcp.doff is only 4 bits, ie. max 15 * 4 bytes */
const u_int8_t *op;
u8 _opt[15 * 4 - sizeof(_tcph)];
unsigned int i, optlen;
/* If we don't have the whole header, drop packet. */
th = skb_header_pointer(skb, par->thoff, sizeof(_tcph), &_tcph);
if (th == NULL)
goto dropit;
/* Malformed. */
if (th->doff*4 < sizeof(*th))
goto dropit;
optlen = th->doff*4 - sizeof(*th);
if (!optlen)
goto out;
/* Truncated options. */
op = skb_header_pointer(skb, par->thoff + sizeof(*th), optlen, _opt);
if (op == NULL)
goto dropit;
for (i = 0; i < optlen; ) {
if (op[i] == TCPOPT_MSS
&& (optlen - i) >= TCPOLEN_MSS
&& op[i+1] == TCPOLEN_MSS) {
u_int16_t mssval;
mssval = (op[i+2] << 8) | op[i+3];
return (mssval >= info->mss_min &&
mssval <= info->mss_max) ^ info->invert;
}
if (op[i] < 2)
i++;
else
i += op[i+1] ? : 1;
}
out:
return info->invert;
dropit:
*par->hotdrop = true;
return false;
}
static struct xt_match tcpmss_mt_reg[] __read_mostly = {
{
.name = "tcpmss",
.family = NFPROTO_IPV4,
.match = tcpmss_mt,
.matchsize = sizeof(struct xt_tcpmss_match_info),
.proto = IPPROTO_TCP,
.me = THIS_MODULE,
},
{
.name = "tcpmss",
.family = NFPROTO_IPV6,
.match = tcpmss_mt,
.matchsize = sizeof(struct xt_tcpmss_match_info),
.proto = IPPROTO_TCP,
.me = THIS_MODULE,
},
};
static int __init tcpmss_mt_init(void)
{
return xt_register_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
}
static void __exit tcpmss_mt_exit(void)
{
xt_unregister_matches(tcpmss_mt_reg, ARRAY_SIZE(tcpmss_mt_reg));
}
module_init(tcpmss_mt_init);
module_exit(tcpmss_mt_exit);