To cut a long story short, that ACK was sent when the socket didn't belong to anybody. Instead of allowing packets that pertain to a socket that belongs to user x
, allow packets that pertain to a connection that was initiated by a socket from user x
.
The longer story.
To understand the issue, it helps to understand how wget
and HTTP requests work in general.
In
wget http://cachefly.cachefly.net/10mb.test
wget
establishes a TCP connection to cachefly.cachefly.net
, and once established sends a request in the HTTP protocol that says: "Please send me the content of /10mb.test
(GET /10mb.test HTTP/1.1
) and by the way, could you please not close the connection after you're done (Connection: Keep-alive
). The reason it does that is because in case the server replies with a redirection for a URL on the same IP address, it can reuse the connection.
Now the server can reply with either, "here comes the data you requested, beware it's 10MB large (Content-Length: 10485760
), and yes OK, I'll leave the connection open". Or if it doesn't know the size of the data, "Here's the data, sorry I can't leave the connection open but I'll tell when you can stop downloading the data by closing my end of the connection".
In the URL above, we're in the first case.
So, as soon as wget
has obtained the headers for the response, it knows its job is done once it has downloaded 10MB of data.
Basically, what wget
does is read the data until 10MB have been received and exit. But at that point, there's more to be done. What about the server? It's been told to leave the connection open.
Before exiting, wget
closes (close
system call) the file descriptor for the socket. Upon, the close
, the system finishes acknowledging the data sent by the server and sends a FIN
to say: "I won't be sending any more data". At that point close
returns and wget
exits. There is no socket associated to the TCP connection anymore (at least not one owned by any user). However it's not finished yet. Upon receiving that FIN
, the HTTP server sees end-of-file when reading the next request from the client. In HTTP, that means "no more request, I'll close my end". So it sends its FIN as well, to say, "I won't be sending anything either, that connection is going away".
Upon receiving that FIN, the client sends a "ACK". But, at that point, wget
is long gone, so that ACK is not from any user. Which is why it is blocked by your firewall. Because the server doesn't receive the ACK, it's going to send the FIN over and over until it gives up and you'll see more dropped ACKs. That also means that by dropping those ACKs, you're needlessly using resources of the server (which needs to maintain a socket in the LAST-ACK state) for quite some time.
The behavior would have been different if the client had not requested "Keep-alive" or the server had not replied with "Keep-alive".
As already mentioned, if you're using the connection tracker, what you want to do is let every packet in the ESTABLISHED and RELATED states through and only worry about NEW
packets.
If you allow NEW
packets from user x
but not packets from user y
, then other packets for established connections by user x
will go through, and because there can't be established connections by user y
(since we're blocking the NEW
packets that would establish the connection), there will not be any packet for user y
connections going through.
The creation of the TCP RST packet is from your rule
-A INPUT -p tcp -j REJECT --reject-with tcp-reset
The default policy (ACCEPT in your case) only applies to packets that do not match any of the rules in your chain. If a packet matches the rule above with the REJECT target, it will not be subject to the default policy and will be REJECTed (and generate a TCP RST) rather than ACCEPTed.
This TCP RST will not match your rule:
-A OUTPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
because it is not RELATED to another established connection and it is not part of an ESTABLISHED connection. It will continue through your rules and match
-A OUTPUT -m limit -j LOG --log-prefix "UNKNOWN_OUTGOING: " --log-level 5
and end up in your log. If you do not want to log these RST packets, either adjust this rule to not match them or insert an earlier rule to match the RST packets and so something with them before they get here.
Something else I'm noticing is that the first packet you are logging is a SYN/ACK packet from a remote webserver, which looks like a response packet from the remote webserver to a SYN packet you would have earlier sent to begin the connection to the remote host on port 80. If you didn't send an initial SYN, I don't think the connection would match 'ESTABLISHED', but if you did send a SYN then I think the connection should mach 'ESTABLISHED'. This could be messing with which rule your RST ends up matching.
Best Answer
Your interpretation is correct.
If you want the whole thing to also apply to UDP packets, you have to add the same set of rules once again, but with
-p udp
instead of-p tcp
. Or just leave out this option and have the rules apply to all packets (though there could be some gotchas with ICMP packets, so it's probably safer to just add both kinds of rules). However, you'll need TCP in the first place to access e.g. Youtube, so even if streaming from Youtube used UDP, you wouldn't be able to watch a stream, because you'll never get this far.The option
-m
selects which kind of match to use. You can match on lots of different criteria, and there's even extensions to iptables (man iptables-extensions
) with even matching modules. Here,-m owner
selects match by ownership of packets, and--gid-owner
specifies to match group ownership. So both options together mean "this rule applies only to packets that are send from someone in groupinternet
".The option
-j
(originally "jump") specifies what to do when the rule matches. You can jump to a different chain, or you canACCEPT
(stop processing rules and send this packet), or you canREJECT
(stop processing rules and ignore this packet).The next two rules allow packets (
ACCEPT
) for special destinations (-d
), no matter what group the sending application is in, and the last rule drops all packets (REJECT
) that didn't match the previous rules. So it's this last rule that does the actual blocking.There are plenty of tutorials for
iptables
on the internet, google a bit and pick one you like if you want to learn more details. Some random links that I found useful in the past:http://www.iptables.info/en/iptables-targets-and-jumps.html
https://www.frozentux.net/documents/iptables-tutorial/