Creating firewall rules using iptables - linux

Is there any way to construct a firewall rule using "iptables" which filters packets on both input and output? I've only been able to find rules like the following which allow you to designate it as applying to packet source (INPUT) or destination (OUTPUT).
iptables -A INPUT -i eth1 -p tcp -s 192.168.1.0/24 --dport 80 -j DROP.
It would make sense though that I should be able to filter packets coming from and going to specific places so that I could end up with a fw table like the following:
pkts bytes target prot opt in out source destination
0 0 ACCEPT all -- * * 172.152.4.0/24 92.3.0.0/16
Any suggestions?
Thanks!

Yes and no.
No because: iptables works by defining how to treat packets based on their categorization into chains (INPUT, OUTPUT, FORWARD, ...) first and only then also on specific characteristics (source or destination address, protocol type, source or destination port, etc). You can never define an iptable rule that does not apply to a specific chain.
INPUT, OUTPUT, and FORWARD are the default chains of the iptables system. INPUT addresses everything with destination localhost (i.e. that is addressed to your network device); OUTPUT applies to everything with source localhost (i.e. that comes from your computer).
Yes because: You can define custom chains. You can do that like so
sudo iptables -N MYCHAIN
then you can send packets from both the INPUT and the OUTPUT (and if you like the FORWARD) chain to MYCHAIN, for instance all the TCP packages from INPUT:
sudo iptables -A INPUT -p tcp -j MYCHAIN
or all the packages from OUTPUT
sudo iptables -A OUTPUT -j MYCHAIN
and then you can define any rule you want for mychain, including
sudo iptables -A MYCHAIN -s 172.152.4.0/24 -d 92.3.0.0/16 -j ACCEPT
which should be more or less the rule you wanted
However, one might argue that it does indeed make sense to keep INPUT and OUTPUT chains seperate. Most users will want to apply much stricter rules on INPUT and FORWARD than on OUTPUT. Also, iptables can be used for routing in which case it makes a fundamental difference if you have an incoming or an outgoing package.

Related

Linux: how to get network stats on tcp (ie excluding udp)?

I've been using /sys/class/net/eno1/statistics/rx_bytes and tx_bytes to gather stats on my network interface. The trouble is, that network has a device (a Silicon Dust HDHOMERUN HDTV tuner) which constantly streams UDP packets at a very high rate that I don't want to monitor. I'd like to remove that traffic from the monitor - perhaps by only looking at TCP packets.
Is there any way to separate out the TCP and UDP stats?
netstat -st gives some info but it's somewhat cryptic - just how big is a 'segment'? The MTU? The man page is silent on that.
$ netstat -st | grep 'segments received'
25449056 segments received
1683 bad segments received
$ netstat -st | grep 'segments sent out'
37860139 segments sent out
Based on this answer from serverfault. If you are using iptables you can add a rule to each of the INPUT and OUTPUT chains which will count every packet which carries TCP in the payload. It is possible that you will need to invoke every iptables command with sudo.
Create the rules:
# Match all TCP-carrying packets incoming on 'eno1' iface
iptables -I INPUT -i eno1 -p tcp
# Match all TCP-carrying packets outgoing through 'eno1' iface
iptables -I OUTPUT -o eno1 -p tcp
Afterwards, you can use iptables -nvxL INPUT or OUTPUT to be presented with the number of bytes processed by the rule:
Chain INPUT (policy ACCEPT 9387 packets, 7868103 bytes)
pkts bytes target prot opt in out source destination
10582 9874623 tcp -- eno1 * 0.0.0.0/0 0.0.0.0/0
In case you already have other rules defined it might be handy to create a separate chain entirely. This is also described in the answer i referenced, though you also want the -i and -o options in the in/out chains respectively. These allow you to filter on a single interface (use -i for INPUT and -o for OUTPUT).
iptables -N count_in # create custom chain named 'count_in'
iptables -A count_in -j RETURN # append RETURN action to chain 'count_in'
iptables -I INPUT -j count_in # insert chain at the top of chain INPUT
iptables -I count_in 1 -i eno1 -p tcp # insert rule that matches all tcp packets on eno1
# and has no action (does nothing)
iptables -nvxL count_in # list chain 'count_in' rules
I am not sure whether the "bytes" counter includes the IP header, or just the TCP segment bytes but it is still probably the closest metric to what you want to measure (TCP-only rx/tx bytes).
Additionally keep in mind that oftentimes rules defined with iptables are not actually saved and will get deleted on a system reboot. To enable them persistently on every reboot you may use the iptables-save and iptables-restore commands. To learn their usage you should probably look in your Linux distro's documentation as well as iptables manual.
Finally, AFAIK iptables is considered legacy by now and it is being slowly replaced by nftables. I myself still have iptables installed in my system by default. If you want to switch/are already using nftables, then you need to translate above commands to the syntax supported by the nft command. There is a utility called iptables-translate available which may help with this. It's purpose is to translate old iptables commands to equivalent nft commands. I mention this mostly for the sake of completeness, you should be just fine using iptables for your particular task if you have it installed.
You can use iptraf-ng.
Install with:
sudo apt install iptraf-ng
This will give you statistics per protocol (IPv4/IPv6/TCP/UDP/ICMP/...) on a specific interface:
sudo iptraf-ng -d eth0
You can also use this to have details per ports:
sudo iptraf-ng -s eth0

Forwarding traffic to custom key chain in iptables

I need help regarding iptables. I have the following iptables rules when i use the command iptables -L
Chain INPUT (policy DROP)
target prot opt source destination
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT icmp -- anywhere anywhere
ACCEPT all -- anywhere anywhere
ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh
Chain FORWARD (policy DROP)
target prot opt source destination
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain MYSSH (0 references)
target prot opt source destination
Now I want to add a rule to the INPUT chain of my filter table that will send all ssh traffic to the MYSSH chain. I have to make sure this new rule follows (not precedes) the RELATED,ESTABLISHED rule, so it doesn't apply to existing connections!
I tried:
iptables -I INPUT 1 -p tcp -m MYSSH --dport 22 -j ACCEPT
but this is not working. Can you please tell me how to do that?
This is kind of a question for Superuser, but okay. I have my admin hat on today. :P
The main thing is that you can use your chain as a target like ACCEPT, REJECT or DROP, so you want to pass it as -j option, i.e.
iptables -A INPUT -p tcp --dport 22 -j MYSSH
would append a rule to pipe all TCP traffic to port 22 through the MYSSH chain to the INPUT chain.
The other question is where to insert this rule. Generally, when I do this kind of stuff manually (these days I usually use shorewall because its easier to maintain), I just work with iptables -A commands and run them in the right order. In your case, it looks as though you want to insert it as the second or third rule, before the catchall
ACCEPT all -- anywhere anywhere
rule (although that might have some additionall conditions that iptables -L will not show without -v; I can't know that). Then we're looking at
iptables -I INPUT 2 -p tcp --dport 22 -j MYSSH
or
iptables -I INPUT 3 -p tcp --dport 22 -j MYSSH
depending on where you want it.
Note, by the way, that if this catch-all rule doesn't have additional conditions that I'm not seeing, the rule below it will never be reached.

In-kernel packet forwarding from one port to multiple ports

On a Linux-based system I need data incoming on a TCP port to be automatically redirected to other 50 local ports without going through user-space's send/recv. Each port needs to receive a copy of all incoming traffic. All ports are local to the same machine.
I've discarded the splice syscall due to the limit of one endpoint being a file. I guess that iptables is the right tool for this purpose, but I can't figure out the right syntax for this purpose. It should be something similar to:
iptables -t nat -A PREROUTING -p tcp --dport <in_port> -j REDIRECT --to-ports <out_port1>-<out_port50>
I wonder e.g. if the option -m multiport is needed.

libipq performance issues

I am making a packet filtering program running on Ubuntu 12.04 which uses libipq as the library for copying packets into userspace. The logic of libipq works fine for me, my issue is that I have noticed a significant performance hit from using libipq to not using libipq. If I remove my iptable rules that I added for my program and let the kernel handle the packets, the speed is 50 MB/s. However, when using libipq and having restored my iptables rule, the speed goes down to 1 MB/s (if i'm lucky), it's usually half of that.
I wonder, could something be wrong with my iptable rules? Could there be a more efficient use of rules, or is libipq simply that inefficient (or my code even though I don't do that much)? Here is the script I use to setup my iptable rules:
#!/bin/sh
modprobe iptable_filter
modprobe ip_queue
iptables -A FORWARD -p icmp -j QUEUE
iptables -A FORWARD -p tcp -j QUEUE
iptables -A FORWARD -p udp-j QUEUE
iptables -A INPUT -p icmp -j QUEUE
iptables -A INPUT -p tcp -j QUEUE
iptables -A INPUT -p udp -j QUEUE
Other than that, my iptable rules are the default set that came with Ubuntu.
NOTE: My setup is for a client and server VM on two different subnets and using my Ubuntu VM to bridge both using NAT and ip masquerading.
Libipq has been deprecated in favour of the newer libnetfilter_queue

Why doesn't my iptables entries block pinging a Xen virtual machine? [closed]

Closed. This question is off-topic. It is not currently accepting answers.
Want to improve this question? Update the question so it's on-topic for Stack Overflow.
Closed 10 years ago.
Improve this question
I'm writing a bash script to add simple firewalling for Xen.
Here's the actual firewall configuration :
Chain INPUT (policy ACCEPT)
target prot opt source destination
RH-Firewall-1-INPUT all -- anywhere anywhere
Chain FORWARD (policy ACCEPT)
target prot opt source destination
RH-Firewall-1-INPUT all -- anywhere anywhere
Chain OUTPUT (policy ACCEPT)
target prot opt source destination
Chain RH-Firewall-1-INPUT (2 references)
target prot opt source destination
ACCEPT all -- anywhere anywhere
ACCEPT icmp -- anywhere anywhere icmp any
ACCEPT esp -- anywhere anywhere
ACCEPT ah -- anywhere anywhere
ACCEPT udp -- anywhere 224.0.0.251 udp dpt:mdns
ACCEPT udp -- anywhere anywhere udp dpt:ipp
ACCEPT tcp -- anywhere anywhere tcp dpt:ipp
ACCEPT all -- anywhere anywhere state RELATED,ESTABLISHED
ACCEPT udp -- anywhere anywhere state NEW udp dpt:ha-cluster
ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:ssh
ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:http
ACCEPT tcp -- anywhere anywhere state NEW tcp dpt:https
REJECT all -- anywhere anywhere reject-with icmp-host-prohibited
I'd like to add a new chain for each of my virtual machines (each of them has a virtual interface called vif1.0, vif2.0, etc). Output interface (bridge) is xenbr0.
Here's what I do (for example to block ping 'in'to domU1, vif1.0) :
iptables -N domUFirewall
iptables -I FORWARD -j domUFirewall
iptables -I INPUT -j domUFirewall
iptables -A domUFirewall -i vif1.0 -p icmp -j DROP
But .. it doesn't work, i'm still able to ping in/out the domU.
Must be something really 'dumb' but I can't find out what's wrong.
Any clues ?
Thx
Since you're using XEN with bridged networking, packets are being intercepted at a level before ordinary iptables commands can influence them. Thus, you'll probably need to use the ebtables command to influence packet routing in the way that you want to.
ebtables/iptables interaction on a Linux-based bridge
ebtables(8) - Linux man page
Xen Wiki * XenNetworking
Original answer left below that will work for other configurations, but not for XEN with bridged networking.
I am going to pretend for the sake of example that the IP address of vif1.0 is 192.168.1.100.
I would redo the logic to not check the input device, but to instead check by IP Address. At the input chain, the packet is coming from (say) device eth0, not from vif1.0. Thus, this rule:
iptables -I INPUT -i vif1.0 -j domUFirewall
that I previously proposed will never match any packets. However, if you do the following, it should do what you want:
iptables -I INPUT -d 192.168.1.100 -j domUFirewall
where in this case the chain domUFirewall is set up by:
iptables -N domUFirewall
iptables -F domUFirewall
iptables -A domUFirewall -p icmp -j DROP
If a given chain is for a single device, then you want to make this check before jumping into the chain, on a rule with the "-j chainName" action. Then, in the chain itself, you never have to check for the device or IP Address.
Second, I would always flush (empty) the chain in your script, just in case you're re-running the script. Note that when you rerun the script, you may get complaints on the -N line. That's OK.
There are other ways you could do this, but to give a different example, I would need to know specifically how your VM is set up -- bridged networking? NAT? Etc. But the example I gave here should work in any of these modes.
Here are some useful links for the future:
Quick HOWTO, Ch14: Linux Firewalls Using iptables
Sandbox a VMware Virtual Machine With iptables

Resources