This file is the README for BSD::Sysctl version 0.09 INSTALLATION perl Makefile.PL make make test make install Building this module requires a FreeBSD system and a C compiler. Support for OpenBSD and NetBSD will appear in future releases. In theory, this module should be able to handle any system that uses a sysctl interface to the kernel. UNINSTALLATION This Perl module has components which will be found in the following directories: .../perl5/site_perl/5.x.x/mach/auto/BSD/Sysctl/* .../perl5/site_perl/5.x.x/mach/BSD/Sysctl.pm .../perl5/5.x.x/man/man3/BSD::Sysctl.3 TESTING This module requires the following module for thorough testing: Test::More This module will use the following modules if they are available: (their absence is not a problem). Test::Pod Test::Pod::Coverage In order to test whether setting sysctl variables works, a number of preconditions must be met. Firstly, the test script t/02-set.t must be run with root privileges (either as root, or via sudo for example). If not, it will bail out gracefully. Secondly, you must choose the sysctl variable you wish to use. The sysctl(8) man page lists a number of variables that can be modified. You must also choose a new value for the variable to store. BE CAREFUL: if you do not know what you are doing, you can render your system unstable, lose network connectivity, lose access to your filesystem and/or cause the system to lock up. If in doubt, a safe choice is a tweak for UDP blackholing: net.inet.udp.blackhole This is usually set to 0, but you can (and often should) set it to 1. This controls how the system behaves when someone (usually a cracker), probes your machine. Finally, two environment variables must be set. The first variable, TEST_BSD_SYSCTL_NAME, holds the name of the variable, and the second variable, TEST_BSD_SYSCTL_VALUE, holds the new value to which the variable should be set. On a Bourne shell, the following commands will work: % export TEST_BSD_SYSCTL_NAME=net.inet.udp.blackhole % export TEST_BSD_SYSCTL_VALUE=1 % sudo make test When these three preconditions are met, the test script will then change the variable to the new value, and then, most importantly, set it back to the initial value. In the unlikely event that the test script crashes half way through, you will have to restore the variable manually to its initial value. HELPING Patches welcome! If you would like to see this module work on other operating systems, but don't particularly wish to hack on the source yourself, and you have a publically accessible machine on the net, and you are fine with the idea of giving me an account on said machine, then drop me a line. I will send you my public key for connecting via ssh. All I need is a shell and a C compiler, and I give you my word that I will not do anything evil. If required, I will connect only from a fixed address (which would allow you to set up an AllowUsers USER@HOST rule in your sshd_config file). IMPLEMENTATION A sysctl variable is usually specified symbolically, such as "net.inet.tcp.sendspace" (also referred to as a MIB). Internally, the kernel operates on an equivalent numeric list (also referred to as an OID). Furthermore, different variables contain different values. They may be numeric or character strings, they may be a single value, a list of values, or a set of key/value pairs. When a sysctl variable is fetched, the module first asks the kernel to convert the symbolic name to its numeric equivalent. If this step fails, the module considers that the variable does not exist. This step is handled by _mib_info(). If this step succeeds, the module now has the list of numeric values (the OID) that corresponds to the variable. It then performs a second call to ask the kernel how the result is to be formatted. It is a reasonable assumption to imagine that different BSD variants (perhaps even between major releases of the same operating system) will use different techniques for performing this step, and so the XS code will probably require a certain amount of conditional compilation. In FreeBSD, the formatting information is returned as a string. For instance, "I" is an integer, "IU" is an unsigned integer, "LU" is an unsigned long, "A" is an ASCII string. More complex variables return the name of the C struct to use to decode the result, for instance the formatting code for "vm.loadavg" is "S,loadavg", which implies that the result should be cast to a "struct loadavg". Sometimes a number of auxilliary header files need to be included in order for the header file that defines the structure in question to be specified completely. The eg/sizeof.c is handy for figuring out what is required. A performance optimisation concerning the formatting information is to map the string names to integers (this means that the results can be dealt with in a switch statement, rather than a long if/else chain. The mapping table is stored in the mibfmt.map file, and is processed by Makefile.PL to produced the C header file needed by the XS file. Once the formatting key has been converted to an integer, the information is saved in the %MIB_CACHE hash table. Each key points to a packed list of integers: +-------------------------+ | format value | +-------------------------+ | count of remaining ints | +-------------------------+ | oid element 1 | +-------------------------+ | oid element 2 | +-------------------------+ | ... | +-------------------------+ | oid element n | +-------------------------+ This information can be unpacked in Perl-space with the following unpack() template: 'i i/i'. When adding other operating systems, new format values may be appended to the end of the mapping file. After this step has been performed, _mib_lookup() may then proceed with fetching the value associated with the variable. The system call is performed, and, assuming no errors, the results are formatted (according to what %MIB_CACHE indicates, and a scalar, or a reference to an array or hash, is returned. Reading the source to the sysctl binary is very instructive. (i.e. /usr/src/sbin/sysctl/sysctl.c on FreeBSD).