Making Your Network Troubleshooting Friendly

Making your network troubleshooting friendly is a potentially large subject. Generally, the debugging or troubleshooting friendliness of your TCP/IP network depends on how you treat the Internet protocol that was designed specifically with debugging in mind: ICMP.

ICMP is the protocol for sending and receiving control messages between hosts and gateways, mainly to provide feedback to a sender about any unusual or difficult conditions en route to the target host.

There is a lot of ICMP traffic, which usually happens in the background while you are surfing the Web, reading mail, or transferring files. Routers (you are aware that you are building one, right?) use ICMP to negotiate packet sizes and other transmission parameters in a process often referred to as path MTU discovery.

You may have heard admins referring to ICMP as either “evil,” or, if their understanding runs a little deeper, “a necessary evil.” The reason for this attitude is purely historical. A few years back, it was discovered that the networking stacks of several operating systems contained code that could make the machine crash if it was sent a sufficiently large ICMP request.

One of the companies that was hit hard by this was Microsoft, and you can find a lot of material on the ping of death bug by using your favorite search engine. However, this all happened in the second half of the 1990s, and all modern operating systems have thoroughly sanitized their network code since then (at least, that’s what we are lead to believe).

One of the early work-arounds was to simply block either ICMP echo (ping) requests or even all ICMP traffic. Now these rule sets have been around for roughly 10 years, and the people who put them there are still scared. There is most likely little or no reason to worry about destructive ICMP traffic anymore, but here we will look at how to manage just what ICMP traffic passes to or from your network.

Do We Let It All Through?

The obvious question becomes, “If ICMP is such a good and useful thing, shouldn’t we let it all through, all the time?” The answer is that it depends.

Letting diagnostic traffic pass unconditionally makes debugging easier, of course, but it also makes it relatively easy for others to extract information about your network. So, a rule like the following might not be optimal if you want to cloak the internal workings of your network:

pass inet proto icmp

In all fairness, it should also be said that you might find some ICMP traffic quite harmlessly riding piggyback on your keep state rules.

The Easy Way Out: The Buck Stops Here

The easiest solution could very well be to allow all ICMP traffic from your local network through, and let probes from elsewhere stop at your gateway:

pass inet proto icmp icmp-type $icmp_types from $localnet
pass inet proto icmp icmp-type $icmp_types to $ext_if

Stopping probes at the gateway might be an attractive option anyway, but let’s look at a few other options that will demonstrate some of PF’s flexibility.

Letting ping Through

The rule set we have developed so far has one clear disadvantage: Common troubleshooting commands such as ping and traceroute will not work. That may not matter too much to your users, and since it was the ping command that scared people into filtering or blocking ICMP traffic in the first place, there are apparently some people who feel we are better off without it. However, if you are in my perceived target audience, you will be rather fond of having those troubleshooting tools available. And with a couple of small additions to the rule set, they will be.

ping uses ICMP, and in order to keep our rule set tidy, we start by defining another macro:

icmp_types = "echoreq"

Then we add a rule that uses the definition:

pass inet proto icmp icmp-type $icmp_types

If you need more or other types of ICMP packets to go through, you can expand icmp_types to a list of those packet types you want to allow.

Helping traceroute

traceroute is another command that is quite useful when your users claim that the Internet isn’t working. By default, Unix traceroute uses UDP connections according to a set formula based on destination. The following rule works with the traceroute command on all forms of Unix I’ve had access to, including GNU/Linux:

# allow out the default range for traceroute(8):
# "base+nhops*nqueries-1" (33434+64*3-1)
pass out on $ext_if inet proto udp to port 33433 >< 33626

This gives you a first taste of what port ranges look like. They are quite useful in some contexts.

Experience so far indicates that traceroute implementations on other operating systems work roughly the same. One notable exception is Microsoft Windows. On that platform, the tracert.exe program uses ICMP echo requests for this purpose. So if you want to let Windows traceroutes through, you need only the first rule, much like letting ping through. The Unix traceroute program can be instructed to use other protocols as well, and will behave remarkably like its Microsoft counterpart if you use its -I command-line option. You can check the traceroute man page (or its source code, for that matter) for all the details.

This solution is based on a sample rule I found in an openbsd-misc post. I’ve found that list, and the searchable list archives (accessible among other places from http://marc.info/), to be a very valuable resource whenever you need OpenBSD or PF-related information.

Path MTU Discovery

The last bit I will remind you about when it comes to troubleshooting is the path MTU discovery. Internet protocols are designed to be device-independent, and one consequence of device independence is that you cannot always predict reliably what the optimal packet size is for a given connection. The main constraint on your packet size is called the maximum transmission unit, or MTU, which sets the upper limit on the packet size for an interface. The ifconfig command will show you the MTU for your network interfaces.

Modern TCP/IP implementations expect to be able to determine the correct packet size for a connection through a process that simply involves sending packets of varying sizes within the MTU of the local link with the “do not fragment” flag set. If a packet then exceeds the MTU somewhere along the way to the destination, the host with the lower MTU will return an ICMP packet indicating “type 3, code 4,” when the local upper limit has been reached. Now, you don’t need to dive for the RFCs right away. Type 3 means destination unreachable, and code 4 is short for fragmentation needed, but the do not fragment flag is set. So if your connections to other networks, which may have MTUs that differ from your own, seem suboptimal, you could try changing your list of ICMP types slightly to let the destination-unreachable packets through:

icmp_types = "{ echoreq, unreach }"

As you can see, this means you do not need to change the pass rule itself:

pass inet proto icmp icmp-type $icmp_types

Now I’ll let you in on a little secret: In almost all cases, these rules are not necessary for purposes of path MTU discovery (but they don’t hurt either). However, even though the default PF keep state behavior takes care of most of the ICMP traffic you will need, PF does let you filter on all variations of ICMP types and codes. If you want to delve into more detail, the list of possible types and codes are documented in the icmp(4) and icmp6(4) man pages. The background information is available in the RFCs.[18]



[18] The main RFCs describing ICMP and some related techniques are 792, 950, 1191, 1256, 2521, and 2765. ICMP updates for IPv6 are in RFC 1885, RFC 2463, and RFC 2466. These documents are available in a number of places on the Net, such as http://www.ietf.org/ and http://www.faqs.org/, and probably also via your package system.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.224.59.145