HOSTS_ACCESS(5)
๐ HOSTS_ACCESS(5) ๐
okay so bestie, this is hosts_access, the File Formats Manual page for host access control files ๐
it's section 5 btw, so it's all about the format of the files. let's get into it ๐ซถ
๐ธ NAME
hosts_access - format of host access control files โจ
๐ DESCRIPTION
okay so this page explains a simple access control language that's based on client patterns (host name/address, user name) and server patterns (process name, host name/address) ๐ฆ examples are at the end, so if you're impatient like me, just skip straight to the EXAMPLES section and get your vibe on ๐
the extended version of the language is in the hosts_options(5) document. ngl this one supersedes the meaning of shell_command as described below, so keep that in mind ๐
quick definitions so we're on the same page:
- daemon is the process name of a network daemon process ๐ง
- client is the name and/or address of a host asking for service ๐
network daemon process names get specified in the inetd configuration file, so go check there if you're lost ๐
โจ ACCESS CONTROL FILES โจ
the access control software checks two files, and the search stops at the very first match ๐ the order goes like this:
- access is granted if a (daemon,client) pair matches an entry in the
/etc/hosts.allowfile ๐ - otherwise, access is denied if a (daemon,client) pair matches an entry in the
/etc/hosts.denyfile ๐ซ - otherwise, access is granted ๐
a non-existing access control file gets treated like it's an empty file ๐ซ so honestly? if you provide no access control files at all, access control is basically turned off ๐
๐ฆ ACCESS CONTROL RULES ๐ฆ
each access control file is made of zero or more lines of text ๐ the lines get processed in order of appearance, and the search wraps up the second a match is found ๐ฅ
here's the lowkey important stuff about the lines:
- a newline gets ignored if a backslash comes right before it ๐งต this lets you break up long lines so they're easier to edit
- blank lines and lines that start with a
#ยดcharacter are ignored ๐ so you can drop comments and extra whitespace in to make the tables easier to read - every other line should follow this format (anything in
[]is optional):
daemon_list : client_list [ : shell_command ]
daemon_list is a list of one or more daemon process names (argv[0] values), server port numbers, or wildcards (more on those below) ๐ง
client_list is a list of one or more host names, host addresses, patterns, or wildcards (see below) that get matched against the client host name or address ๐
the more complex forms daemon@host and user@host are explained in the sections on server endpoint patterns and client username lookups, respectively ๐ซถ
list elements should be separated by blanks and/or commas, bestie ๐
with the exception of NIS (YP) netgroup lookups, all access control checks are case insensitive, soHOSTandhostare the same tea โ
๐ PATTERNS ๐
the access control language gives you these patterns to play with:
.tue.nlยดโ a string that begins with a.ยดcharacter ๐ a host name matches if the last components of its name match the pattern. so the pattern.tue.nlยดmatches the host namewzv.win.tue.nlยด131.155.โ a string that ends with a.ยดcharacter ๐ธ a host address matches if its first numeric fields match the given string. for example, the pattern131.155.ยดmatches the address of (almost) every host on the Eindhoven University network (131.155.x.x) ๐ฆ@netgroupโ a string that begins with an@ยดcharacter gets treated as an NIS (formerly YP) netgroup name โจ a host name matches if it's a host member of that netgroup. netgroup matches are not supported for daemon process names or for client user names ๐
on Debian systems, support for NIS netgroups has been disabled since package version 7.6.q-33, so if your netgroup patterns aren't working, that's probably why ๐
n.n.n.n/m.m.m.mโ an expression like this gets read as anet/maskยดpair ๐ง an IPv4 host address matches ifnetยด equals the bitwise AND of the address and themaskยด ๐งฎ for example, the net/mask pattern131.155.72.0/255.255.254.0ยดmatches every address from131.155.72.0ยดthrough131.155.73.255ยด๐ญ also,255.255.255.255ยดis not a valid mask value, so a single host can be matched just by its IP ๐ซถn.n.n.n/mmโ an expression like this gets read as anet/masklengthยดpair, wheremmยดis the number of consecutive1ยดbits in the netmask applied to then.n.n.nยดaddress ๐ข[n:n:n:n:n:n:n:n]/mโ an expression like this gets read as a[net]/prefixlenยดpair ๐ง an IPv6 host address matches if theprefixlenยดbits ofnetยดequal theprefixlenยดbits of the address. for example, the [net]/prefixlen pattern[3ffe:505:2:1::]/64ยดmatches every address from3ffe:505:2:1::ยดthrough3ffe:505:2:1:ffff:ffff:ffff:ffffยด๐/path/to/fileโ a string that begins with a/ยดcharacter is treated as a file name ๐ a host name or address matches if it matches any host name or address pattern listed in that named file. the file format is zero or more lines, each with zero or more host name or address patterns separated by whitespace ๐ a file name pattern can be used anywhere a host name or address pattern can be used, so you can totally mix and match ๐*and?โ wildcards can be used to match host names or IP addresses ๐ this method of matching cannot be used in conjunction withnet/maskยดmatching, host name matching beginning with.ยด, or IP address matching ending with.ยด๐
โจ CLIENT USERNAME LOOKUP โจ
okay so if the client host speaks RFC 931 or one of its descendants (TAP, IDENT, RFC 1413) ๐ต๏ธโโ๏ธ the wrapper programs can go digging for info about who actually owns the connection. Any username they find gets logged next to the client host name, and you can even match on it with patterns like:
daemon_list : ... user_pattern@host_pattern ...
The daemon wrappers can be set up at compile time to do rule-driven username lookups (that's the default ๐ ) or to always poke the client host no matter what. With rule-driven lookups, the rule above only triggers a lookup when both the daemon_list and the host_pattern match. Iconic efficiency, honestly.
A user pattern works the same way as a daemon process pattern, so all the same wildcards apply. Just know that netgroup membership is not supported here ๐ โโ๏ธ. And bestie, don't get too carried away with username lookups, because there are some real gotchas:
- The client username info can't be trusted when you need it most, aka when the client system has been compromised ๐. Honestly, ALL and (UN)KNOWN are the only user name patterns that make sense.
- Username lookups only work with TCP-based services, and only when the client host is running a suitable daemon. Everywhere else, the result is
"unknown". - A well-known UNIX kernel bug can cause loss of service when a firewall blocks username lookups ๐ญ. The wrapper README document walks you through how to check whether your kernel has this bug.
- Username lookups can cause noticeable delays for non-UNIX users. The default timeout is 10 seconds, which is too short for slow networks but long enough to irritate PC users ๐.
Selective lookups can totally fix that last one. For example, a rule like:
daemon_list : @pcnetgroup ALL@ALL
matches members of the pc netgroup without doing any username lookups, but still does them for every other system. Main character problem solved โจ.
๐ต๏ธโโ๏ธ DETECTING ADDRESS SPOOFING ATTACKS ๐ต๏ธโโ๏ธ
Okay, this part is kind of scary. A flaw in the sequence number generator of many TCP/IP implementations lets intruders easily impersonate trusted hosts and break in through things like the remote shell service ๐ฑ. The IDENT (RFC931 etc.) service can be used to catch this and other host address spoofing attacks.
Before accepting a client request, the wrappers can use the IDENT service to figure out that the client never actually sent the request at all. When the client host provides IDENT service, a negative IDENT lookup result (the client matches UNKNOWN@hostยด) is strong evidence of a host spoofing attack ๐จ.
A positive IDENT lookup result (the client matches KNOWN@hostยด) is way less trustworthy ๐ซค. An intruder can spoof both the client connection and the IDENT lookup, although that's much harder than spoofing just the client connection. It's also possible that the client's IDENT server is simply lying.
Note: IDENT lookups donยดt work with UDP services. No IDENT for you, UDP ๐.
๐ EXAMPLES ๐
The language is super flexible, so different kinds of access control policy can be written with minimal fuss ๐. Even though it uses two access control tables, the most common policies work fine with one table being trivial or even empty.
When you read the examples below, keep these three things in mind ๐ง : the allow table gets scanned before the deny table, the search stops as soon as a match is found, and access is granted when no match is found at all.
The examples use host and domain names. You can make them stronger by adding address and/or network/netmask information, which reduces the impact of temporary name server lookup failures ๐ธ.
๐ MOSTLY CLOSED ๐
In this setup, access is denied by default. Only explicitly authorized hosts get in ๐ช.
The default policy (no access) is set up with a trivial deny file:
/etc/hosts.deny:
ALL: ALL
This denies all service to all hosts, unless they're permitted by entries in the allow file.
The explicitly authorized hosts go in the allow file. For example:
/etc/hosts.allow:
ALL: LOCAL @some_netgroup
ALL: .foobar.edu EXCEPT terminalserver.foobar.edu
The first rule lets in hosts from the local domain (no . in the host name) and members of the some_netgroup netgroup ๐ซถ. The second rule lets in all hosts in the foobar.edu domain (notice the leading dot!), except for terminalserver.foobar.edu.
๐ MOSTLY OPEN ๐
Here, access is granted by default, and only explicitly specified hosts get turned away ๐ โโ๏ธ.
Since the default policy (access granted) makes the allow file redundant, you can just leave it out ๐ซ . The explicitly non-authorized hosts go in the deny file. For example:
/etc/hosts.deny:
ALL: some.host.name, .some.domain
ALL EXCEPT in.fingerd: other.host.name, .other.domain
The first rule denies some hosts and domains all services. The second rule still lets finger requests through from other hosts and domains ๐.
๐ชค BOOBY TRAPS ๐ชค
This one is giving sneaky genius ๐. The next example permits tftp requests from hosts in the local domain (notice the leading dot). Requests from any other hosts get denied. Instead of the requested file, a finger probe gets sent to the offending host, and the result is mailed to the superuser ๐ฌ.
/etc/hosts.allow:
in.tftpd: LOCAL, .my.domain
/etc/hosts.deny:
in.tftpd: ALL: (/usr/sbin/safe_finger -l @%h | \
/usr/bin/mail -s %d-%h root) &
The safe_finger command comes with the tcpd wrapper and should be installed somewhere sensible ๐ง. It limits the possible damage from data sent by the remote finger server, and it gives better protection than the standard finger command ๐ .
The expansion of the %h (client host) and %d (service name) sequences is covered in the section on shell commands ๐ค.
Warning: do not booby-trap your finger daemon, unless you are prepared for infinite finger loops ๐๐.
On network firewall systems, this trick can go even further ๐ฅ. The typical network firewall only offers a limited set of services to the outer world, so all the other services can be "bugged" just like the tftp example above. The result is an excellent early-warning system ๐จ๐ฆ.
๐งฏ DIAGNOSTICS ๐งฏ
Errors get reported when any of these happen ๐ฌ: a syntax error is found in a host access control rule; an access control rule is longer than the capacity of an internal buffer; an access control rule isn't terminated by a newline character; the result of a %<letter> expansion would overflow an internal buffer; or a system call fails when it really shouldnยดt. Everything gets reported via the syslog daemon ๐.
๐ FILES ๐
/etc/hosts.allowโ (daemon,client) pairs that are granted access โ/etc/hosts.denyโ (daemon,client) pairs that are denied access ๐ซ
๐ SEE ALSO ๐
hosts_options(5)โ extended syntax ๐งฉtcpd(8)โ tcp/ip daemon wrapper program ๐ก๏ธtcpdchk(8),tcpdmatch(8)โ test programs ๐งช
๐ BUGS ๐
If a name server lookup times out, the host name won't be available to the access control software, even though the host is registered ๐.
Domain name server lookups are case insensitive, but NIS (formerly YP) netgroup lookups are case sensitive ๐. Watch your capitalization, bestie.
๐งโ๐ป AUTHOR ๐งโ๐ป
Wietse Venema (wietse@wzv.win.tue.nl) Department of Mathematics and Computing Science Eindhoven University of Technology Den Dolech 2, P.O. Box 513, 5600 MB Eindhoven, The Netherlands
okay that's the whole page, bestie ๐โจ go be a legend with your access rules ๐. Love you, mwah ๐ซถ HOSTS_ACCESS(5) ๐ฆ๐
๐ฆ where this page comes from
- debian trixie: libwrap0 7.6.q-36 ยท TCP-wrappers
- ubuntu noble: libwrap0 7.6.q-33 ยท TCP-wrappers
- ubuntu questing: libwrap0 7.6.q-36build1 ยท TCP-wrappers
- ubuntu resolute: libwrap0 7.6.q-36build2 ยท TCP-wrappers
- ๐ girlified by anthropic/claude-haiku-5.5 on : a language model's rewrite of the original, under its terms