Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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?

share|improve this question
up vote 1 down vote accepted

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 and src port 3000 or dst host 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 and 'tcp[0:2] >= 3000' and 'tcp[0:2] <= 3999' \) or
  \( dst host and 'tcp[2:2] >= 3000' and 'tcp[2:2] <= 3999' \) \)

Replace 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.

share|improve this answer
Very detailed explanation! – Xiè Jìléi Nov 11 '10 at 1:32

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

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