Currently, I must sudo tcpflow -i lo
as root user, I want to grant the lo
interface and TCP port range 3000-3999 of all interfaces
to user1, how to do that?
1 Answer
You need to be root to do the kind of snooping that tcpflow and tcpdump do. So you either need sudo
or a setuid root wrapper.
Well, technically all you need the CAP_NET_RAW
capability. If you install the libcap2-bin
package¹, you can use the setcap
command to create a “setcap-CAP_NET_RAW
” wrapper around tcpflow
, rather than a setuid wrapper. But that only helps make a security hole in the wrapper be a little less damaging (a user who obtains CAP_NET_RAW
access can probably gain root with little effort).
You can use sudo
or a setuid root wrapper to let user1 run a command like tcpflow -i eth0 tcp and \( src host 1.2.3.4 and src port 3000 or dst host 1.2.3.4 and src port 3000 \)
. Note that you can't just let user1 run an arbitrary tcpflow
command: that would allow user1 to run things like tcpflow -r … -r /path/to/foo
and read (at least partially) /path/to/foo
with root permissions.
I don't think you'll be decently able to allow the user to specify an expression to match packets. Rather than give extra permissions to run tcpflow
, I suggest giving extra permissions to run a fixed tcpdump
command (writing to stdout, let the user redirect into a file if necessary). Then the user can run tcpflow -r
to analyze tcpdump
output (even in real time, through a pipe).
Now for lo
, allow user1 to run this exact command:
tcpdump -i lo tcp
For other interfaces, I think the following command selects tcp ports 3000–3999 (but make extensive tests to be sure):
tcpdump -i eth0 tcp and \( \
\( src host 1.2.3.4 and 'tcp[0:2] >= 3000' and 'tcp[0:2] <= 3999' \) or
\( dst host 1.2.3.4 and 'tcp[2:2] >= 3000' and 'tcp[2:2] <= 3999' \) \)
Replace 1.2.3.4 by the IP address associated with the interface. I don't have a good solution to offer if the IP address isn't fixed: if you read it from ifconfig
output or otherwise at the beginning of the wrapper script, it's open to a race condition.
My recommendation for a wrapper is not to use a shell script (I don't know if any of the shells in Debian is suitable for writing setuid scripts — shells tend to use a lot of environment variables), but rather Perl (where this kind of thing is explicitly supported), like this:
#!/usr/bin/perl -T
exec '/usr/sbin/tmpdump', '-i', 'lo', 'tcp'
Make the script an ordinary executable (mode 755), and allow user1 to run it through sudo.
¹
For other Linux distributions: you need kernel 2.6.24 or above and the setcap
command.