View from the Trenches: Virtual Curfews

Pulling together the pieces to meet real-world customer requests, and the value of learning from our mistakes.

Recently a client had an interesting request for me. It seems that his teenage daughter had done a very strange thing: she had requested a curfew on her Internet time, as it was interfering with her studies and sleep. Dad had been doing this simply by pulling the cat5 leading to her machine out of the hub, but this was clumsy and mechanical and it involved crawling under a desk. A better solution, involving his Debian Woody firewall, was in order. Not being a total firewall guru, he turned to me.

I took a bottom-up approach to the problem. First, using my own LAN, I perfected an ipchains rule that would block access from a given machine to the outside world, while still allowing intra-LAN access for things like printing to a networked printer.

ipchains -I input -s $VICTIM -d ! $SUBNET -i eth0 -j REJECT

where VICTIM is her IP address and SUBNET is something like, that is, the IP address with the last octet zero (usually) and the correct number of bits after the slash. Oddball subnets are left as an exercise for the reader; likewise, one could substitute a subnet for VICTIM as well.

So far, so good, except you have to make sure VICTIM really is VICTIM all the time. With plain vanilla DHCP, that's not guaranteed unless you make it so. Look at your logs (/var/log/syslog or /var/log/messages) for the MAC address of your target machine, and then add a static host to your dhcpd.conf, like this:

  host artoo {
     hardware ethernet 01:23:45:ab:cd:ef;
     default-lease-time 43200;

Don't forget the semicolons at the end of the lines after editing, or DHCP won't start. /etc/init.d/dhcpd restart works on most systems to do the restart; make sure to test your work. The best way to do so is to refresh the interface on the client machine and check the logs for the appropriate DHCP ACK. Not doing so can be embarrassing.

Now, we have to script this thing. You could take the easy way out and write two little scriptlets, one to insert the rule and one to delete it. Having been a parent before, however, I knew that one should make allowances for both groundings and rewards or special circumstances. Furthermore, a single initscripts-style script would be easy to maintain, once all the details were fleshed out.

I came up with five cases: UP, DOWN, GROUND, FREE and STATUS. GROUND and FREE are used if the kid is grounded or, conversely, allowed to surf all night. I used touch files in /var/run to indicate the status. Normally, writing this big case statement would be a chore, but Debian includes /etc/init.d/skeleton, which provides a nice framework for such a thing. SuSE does too; Red Hatters and others can use DHCPD's fairly straightforward init script instead, if you want to play along instead of skipping to the end.

One more piece to this puzzle, and we're ready to install. We have to have a way to run these scripts whether or not Dad is around. Particularly because, under house rules, one is allowed to arise at 4am and finish one's homework. Cron is the obvious choice for this; here are the entries:

30 23 * * * /usr/local/bin/kidnet down
00 04 * * * /usr/local/bin/kidnet up

For those who are rusty, the fields are minute, hour, day of the month, month, day of the week (0 and 7 are both Sunday) and command. The easy way to install these lines is to use crontab -e and cut and paste. First, though, make sure root's EDITOR value is set the way you want. Debian throws you into nano if you don't, and if you have long lines in the file, it could be painful.

Having tested all this, I show up at my friend's house ready to drop this kit in and have it just work, only to discover that, no, he doesn't have ipchains, he has iptables. Oops. Well, we just have to fix this on the fly. Shouldn't be a big deal, should it? Simply change

ipchains -I input -s $VICTIM -d ! $SUBNET -i eth0 -j REJECT


iptables -I INPUT -s $VICTIM -d ! $SUBNET -i eth0 -j REJECT

and the matching delete rule likewise, and all is well, right?


There's a little subtlety in iptables that says you can't jump to REJECT on INPUT, nor can you (as I discovered) specify the inbound interface on FORWARD or OUTPUT. With greater flexibility comes greater complexity. What I ended up doing is specifying the outbound interface in the FORWARD rule, thereby making the rule a variable:

iptables -I $RULE

By putting the cutoff in the FORWARD rule, I ensured that only masquerading would be affected and not anything inside the LAN. Thus, the -d parameter would be redundant.

Listing 1. Final Script for iptables

Of course, there is room for improvement here. If the system goes down when the curfew arrives and comes back up after it should be down, it stays up until the next day. Also, if the status files get confused, you have to clean out /var/run manually. You could catch the error caused when doing kidnet up when the interface is up already, or you could do a little dance with grep and prevent it from happening. But my particular customer already is Linux-savvy from a user standpoint, and he takes good notes. If your audience is similar, this should be quite sufficient. If you're getting paid to make it really slick, then you've got another hour of work you can bill.

I learned a couple of things from this little adventure. One is that real-world applications rarely touch only one area of the system. In this case, we touched shell programming, crontab, DHCP and firewalling. It's a fairly simple task for the experienced sysadmin, but you won't find it in the average HOWTO. The other is thing I learned is to make sure what I think is the client's configuration actually is the client's configuration before going on site--it saves a lot of shotgun programming. On the other hand, even if you do screw up, if you're honest about it and fix it in a timely manner, it can earn you repeat business, perhaps more so than if you simply dropped it in. You're showing clients you'll be there for them. Repeat business, delightful words for a penguin-head to hear, down here in the trenches.

Glenn Stone is a Red Hat Certified Engineer, sysadmin, technical writer, cover model and general Linux flunkie. He has been hand-building computers for fun and profit since 1999, and he is a happy denizen of the Pacific Northwest.




Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.

Re: View from the Trenches: Virtual Curfews

Anonymous's picture

Ipchains is far too old soon even to mention. Sorry, but I just had to say this. You must be more a writer than a sysadmin :)
Having had to learn both ipchains and iptables I can only say this - forget the older and learn only the newer. It's WAY better.
Oh and btw, if you had checked the iptables howto at, you'd know that there exists a mac target for the iptables. Hence - no need to hack around the DHCP on a two-pc-lan. Of course if you insist on being so orderly..
Of course, being so orderly.. you would probably like to use a side-chain for all the traffic from the little girl's pc, in case there would be more than one rule in the future.

Re: View from the Trenches: Virtual Curfews

Anonymous's picture

I think fcron would be able to handle the potential problem of the machine being down when a command was scheduled to be run:

"Fcron also includes a useful system of options, which can be applied either to every lines following the declaration or to a single line. Some of the supported options permit to:

* run jobs one by one,
* set the max system load average value under which the job should be run,
* set a nice value for a job,
* run jobs at fcron's startup if they should have been run during system down time,
* mail user to tell him a job has not run and why,
* a better management of the mailing of outputs ... "

Re: View from the Trenches: Virtual Curfews

Anonymous's picture

For people looking for this type of functionality, I recommend Censornet.

You can limit internet time by user or workstation. It has a nice GUI for administration and reports. There is a fairly active forum of users (and support techs).

It's GPL and free for download. They do take donations (I was glad to do this) so you can say, "How much was it worth to me to get a really nice customized Debian distro that does exactly what I was looking for...".

Hope this helps.

Re: View from the Trenches: Virtual Curfews

synthetoonz's picture

I did something similar, but hadn't thought of reconfiguring the network to do it.

Our rules were more simple -- the adults in the house have to go to work, so they need an appropriate amount of sleep. Therefore, the loud and badly behaved teenager in the house had to be forcibly prevented from playing SOCOM Online (an endeavor he insists must be done every waking moment) at unrealistic times of the night (or morning.)

So, I wrote a perl script that runs on the system acting as the firewall/dsl router.
cron runs the script every five minutes.
A list of up and down times is kept in the script.
If the current time is a down time, then the script refers to the list of the adult's computers in the house.
If any of the adult's computers respond to ping, then the script ends.
If none of the adult's computers are up, then the script shuts down the system. Totally.

Why waste electricity on something that isn't being used?

I was soooooo pleased with myself the first time it worked ;-)

(Oh, yes, and all the adult's computers require a password in order to boot.)

Re: View from the Trenches: Virtual Curfews

Anonymous's picture

Excellent article. This might be something that would integrate well into a "family firewall" product and be handled by a web interface easily. I'm sure I could find some people who would adopt such a product for a small one-time price. My parents would have loved to have had this too. :-)

I enjoyed how you insightfully drew out some real world consulting experience in addition to the fun technical perspective. Great mix of the two that I appreciated.