fixed netfilter errors and missing dependencies
This commit is contained in:
parent
d3034284d5
commit
0e29cb4fa1
@ -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
|
||||
|
@ -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.
|
||||
|
@ -1 +0,0 @@
|
||||
../../platform/generic/system.dts
|
@ -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*/
|
||||
|
@ -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 */
|
@ -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 */
|
@ -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 */
|
||||
|
@ -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*/
|
||||
|
@ -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*/
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
@ -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*/
|
@ -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 */
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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 */
|
@ -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
|
@ -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;
|
||||
};
|
||||
|
@ -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
|
@ -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);
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
@ -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);
|
@ -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");
|
@ -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);
|
@ -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);
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
Loading…
x
Reference in New Issue
Block a user