2

I want this user not to be allowed to bind ports (effectively creating world-accesible servers, though on ports >1024) on the Internet interface, but be allowed to do in the loopback interface on certain ports.

Is there a magic iptables trick or something to get this effect?

This server does not run SELinux, and it would be too overkill to set it up now, so I would prefer other solutions, if any.

4
  • Block all inbound connections on the external interfaces by default, and whitelist the specific ports you need to work? If he can bind, but nobody outside can connect, does that fix it? May 5, 2013 at 13:36
  • That would force me to restrict all users to create servers, but I want to limit only that user.
    – Alicia
    May 5, 2013 at 13:40
  • The "easiest" thing I can think of is to give the specific user their own VM, where you can set the rules differently than for the other users who use your original server. I'm not saying there's no way to do exactly what you want without changing the architecture, but I have to wonder if making a separate VM would fix other (currently unexpected) problems in the future. May 5, 2013 at 14:16
  • Too overkill. All that user needs is a reverse SSH tunnel for his service to be available on the machine.
    – Alicia
    May 5, 2013 at 14:26

1 Answer 1

0

I don't see a possibility to force sockets to a certain port but you can prevent other ports being successfully used. This can be done by iptables and its owner module. You can drop all replies from processes belonging to this user from disallowed addresses.

If this is an option for you and you don't know how to do it let me know and I will deliver some code in addition.

Edit 1

The solution is to block every packet from this user which belongs

  1. neither to a connection which this user has opened (i.e. he is not listening on a port at all)
  2. nor sends from an allowed port.

You are right, owner does not work in INPUT but we need it in OUTPUT only. To make things easier (and faster) we mark all allowed packets (from this user) with 42, all disallowed with 41. Marking the disallowed ones would be enough.

It works this way:

  1. All packets (connections) from that user are selected for special handling
  2. All packets are marked with 41 (disallowed). For allowed connections this is overwritten later.
  3. All connections with a locally generated first packet are allowed
  4. Everything left was not created locally. Drop everything not from lo
  5. Now allow all connections with an allowed source port (sorce of the reply i.e. local port)
  6. Last step: Drop all packets which are marked with 41.

Edit 2

The approach with the nat table failed (for incoming connections because only the first packet of a connection is checked in nat and the first is the incoming one which hits -t nat INPUT only where the owner module is not available). Thus all checking and marking is done in the default table (filter) now.

The script:

#!/bin/bash

# MODIFY NEXT LINE
user=hl

# iptables -F
# iptables -t nat -F
# iptables -t mangle -F

iptables -N user_x &>/dev/null
iptables -N user_x_ports &>/dev/null
iptables -N user_x_allow &>/dev/null
iptables -N user_x_block &>/dev/null


# configure chain user_x_allow  
iptables -A user_x_allow -j CONNMARK --set-mark 42
iptables -A user_x_allow -j ACCEPT

# configure chain user_x_block
iptables -A user_x_block -j CONNMARK --set-mark 41
iptables -A user_x_block -j DROP

# configure chain user_x_ports
# one line for each allowed port  
iptables -A user_x_ports -p tcp --sport 1234 -j user_x_allow

# configure chain user_x
iptables -A user_x -m conntrack --ctstate NEW -j user_x_allow
iptables -A user_x \! -o lo -j user_x_block
iptables -A user_x -j user_x_ports
iptables -A user_x -j user_x_block

# the first two rules are just for checking what happens with "iptables -L -nv"
#       and can be commented out
index=1
iptables -I OUTPUT "$index" -m owner --uid-owner $user; ((index++)) # just count
iptables -I OUTPUT "$index" -m owner --uid-owner $user -m connmark --mark 0; ((index++)) # just count
iptables -I OUTPUT "$index" -m connmark --mark 41 -j DROP # or reset
((index++))
iptables -I OUTPUT "$index" -m connmark --mark 42 -j ACCEPT
((index++))
# this matches non-marked (new) connections only
iptables -I OUTPUT "$index" -m owner --uid-owner $user -j user_x
((index++))
7
  • iptables owner module does not work for INPUT table (man iptables-extensions). I don't see how you could use this to forbid a user to bind a server. If you know, please write an example rule.
    – Alicia
    May 5, 2013 at 12:58
  • @ntrrgc See the edit May 6, 2013 at 0:54
  • Cool, I took a time to understand it and it seems to make sense (it would not restrict the user to bind the port, but would cut all undesired connections). Bad part is I tried it in a VM and it does not seem to work. I did set up the filter (for a user x, allowing only port 1234), set up a server with the user x on the different port 1245 but nevertheless I am able to connect to that process from the outside. I made a screencast showing it... lasaña.rufian.eu/CPZS (link valid for a week)
    – Alicia
    May 6, 2013 at 23:49
  • @ntrrgc Doesn't work in my VM either. What a pity, would have been so nice... Problem found: The nat table is used for the first packet of a connection only. Thus replies to connections opened from the outside are not handled there at all. Those must be handled in another table. This time I test it before posting... May 7, 2013 at 0:25
  • @ntrrgc Done (or rather: "next try"?) May 7, 2013 at 2:59

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.