secnet(8)
π NAME π
secnet β VPN router daemon
okay so welcome to the secnet(8) page, straight out of the System Manager's Manual, and bestie by the end of this you are gonna be so good at VPNs. group-chat energy only, but every single fact stays, periodt.
πΈ SYNOPSIS πΈ
secnet [OPTIONS]
π¦ DESCRIPTION π¦
secnet lets you build virtual private networks that stretch across multiple separate sites. That's it, that's the whole main character moment β separate sites, one big connected VPN vibe. β¨
π OPTIONS π
--verbose,-vβ turn on the extra diagnostics, we love a chatty daemon π¬--nowarnings,-wβ suppress warnings (the little "hey maybe don't" messages)--helpβ display the usage message--versionβ display the version string--nodetach,-nβ don't go into the background. The default behaviour is to become a daemon during startup, so this is your "no bestie stay with me" flag π«Ά--silent,--quiet,-fβ suppress error messages--debug,-dβ enable debug messages--config,-cPATH β specify the configuration file. The default is/etc/secnet/secnet.conf--just-check-config,-jβ check the configuration and then exit, like a vibe check for your config file π--sites-key,-sKEY β the configuration file key that defines the active sites. The default issites
π CAPABILITY NEGOTIATION π
Sites negotiate with each other during key exchange to figure out which cryptographic algorithms and other features β these are called capabilities β each of them supports. Capabilities get assigned small integer numbers. In lots of cases you can assign capability numbers yourself in the configuration file (more on that below), but honestly secnet's default assignments are often perfectly fine. Slay.
Capability numbers between 0 and 7 inclusive are reserved for local use: secnet will never touch them without explicit configuration. This is lowkey useful if you want to migrate from one set of parameters for a particular cryptographic algorithm to different, incompatible parameters for that same algorithm. Other capability numbers get assigned by default by various kinds of closures β see the descriptions below for the deets. π
It is essential that a capability number mean the same thing to each of a pair of peers. You can configure a site so it uses different capability numbers for the same feature when talking to different peer sites, but bestie that is likely to be way more confusing than useful. Don't do it to yourself. π
π CONFIGURATION FILE π
π Overview
The default configuration file is /etc/secnet/secnet.conf. You can override that with the --config option.
The configuration file defines a dictionary β a mapping from keys to values β of configuration information for secnet. It's recursive in nature, i.e. values may themselves include dictionaries. Any node in that nested structure can be identified by a path, which is the sequence of keys you need to walk from the root to reach it, separated by / characters. See Paths below for how that gets used. π§
And here's the iconic part: when a key is looked up in a dictionary, if it can't be found there, it gets sought in the parent dictionary, and so on all the way back to the root. For instance, each site must contain the resolver key, but in a typical configuration there's no point having different resolvers for each site. So resolver gets defined at the root and is thus automatically incorporated into all sites. Inheritance, but make it network config. π
β Whitespace
Whitespace, including newlines, is ignored β except to the extent that it bounds other symbols.
Comments begin with # and continue to the end of the line. Comments are ignored. (yes bestie, comment your config, future you says thank you)
π¦ Inclusion
A file may be recursively included into the configuration file using a line of the form:
include PATH
This is handled at a higher level than the main parser, and so it precludes the possibility of using the string include for any other purpose. (one job, and she's doing it β¨)
πΈ Assignments
The configuration file contains one or more assigments. Each assignment is written:
key [=] list;
i.e. the equals sign is optional. The semicolon is mandatory in all contexts. No semicolon, no slay.
Keys start with a letter or _ and continue with any numbers of letters, digits, _ and -.
Each key is a list of one or more values, separated by commas. The possible value types are boolean, string, number, dictionary, path and closure evaluation.
π Strings
Strings are contained within "double quotes". There is (currently) no escape syntax and no way to include quotes inside strings.
Example:
filename "/var/log/secnet";
π₯ Numbers
Numbers are encoded in decimal and do not include a sign. Numbers must lie in the range 0 to 4294967295.
Example:
mtu 1400;
π«Ά Dictionaries
Dictionaries consist of one or more assignments, in the same syntax as given above, enclosed in { and }.
Example:
system {
userid "secnet";
pidfile "/var/run/secnet.pid";
};
π§ Paths
Paths allow a key already defined in the configuration to be aliased.
Paths consist of a sequence of keys separated by /. If the path starts with a / then it's an absolute path and the search starts at the root of the configuration. Otherwise it's a relative path and starts in the containing dictionary or in any of its parents, down to and including the root. If there's more than one match, the one furthest from the root "wins". π
The value of a path is the list assigned to the key it refers to. Lists are flattened; for example if a key is defined as a list of two paths, and each of those refers to a list of two integers, the original key is therefore defined to be a list of four integers β not a list consisting of two lists. Flattened. Like my entire personality. π
It is not possible to refer to a later key using a path. No looking forward, only back.
Example:
vpn {
test {
kakajou vpn-data/test/kakajou/kakajou;
araminta vpn-data/test/araminta/araminta;
deodand vpn-data/test/deodand/deodand;
all-sites kakajou,araminta,deodand;
};
};
all-sites vpn/test/all-sites;
Here, each of vpn/test/kakajou, vpn/test/araminta and vpn/test/deodand are defined as aliases to values defined elsewhere. vpn/tests/all-sites is defined as the list of all three of those values, and all-sites is then defined to be an alias for that.
π Booleans
The (single-element) paths false, no and nowise are predefined and refer to a boolean false value. Similarly true, yes and verily point at a boolean true value.
In all six cases, variants with just the first letter capitalized, and with all letters capitalized, are also provided. So many ways to say yes. π
Example:
random randomfile("/dev/urandom",no);
π Closure Evaluation
Closure evaluation uses the following syntax:
CLOSURE ( ARGUMENTS )
CLOSURE may be a path referring to a closure, or may itself be a closure evaluation.
ARGUMENTS is a list of zero or more values, separated by commas. As a shortcut, if the arguments consist of a single dictionary, the parentheses may be ommitted:
CLOSURE { ... }
Example:
sites map(site, vpn/test/all-sites);
When a closure is evaluated it returns a value (a list, much as above) and may also have side effects (which may be immediate or may be deferred to some later phase of execution). A list of built-in closures is given below. β¨
π Mandatory Keys
Two keys are mandatory. system must be a dictionary in which the following keys can be looked up:
logβ A log closure; see thelogfiledocumentation below. The destination for log messages. Mandatory.useridβ A string. The userid to run as after dropping privilege. Optional.pidfileβ A string. The path to write a pidfile. Optional.
sites should be a list of site closures; see the site documentation below. This defines the collection of tunnel endpoints that secnet will communicate with.
Recall the recursive lookup logic described in Overview above: if (for instance) log is defined in the top level dictionary but not in system, it will nevertheless be found when looked up in the latter. Inheritance stays winning. π«Ά
π CLOSURES π
secnet contains a collection of built-in closures with names (i.e. single-element paths) given below.
Most of them return anonymous closures of various types, which are described contextually.
πΈ adns
adns(DICT) => resolver closure
- DICT β This either be empty or contain the single key
config, with a string value giving configuration to supply to ADNS. This might be read from a file usingreadfile.
A resolver closure is a means of converting hostnames into network addresses. β¨
π¦ diffie-hellman
diffie-hellman(MODULUS, GENERATOR[, CHECK]) => dh closure
- MODULUS β String. The prime modulus p in hex.
- GENERATOR β String. The generator g in hex.
- CHECK β Boolean. If true (the default) then check if p is prime.
A dh closure defines a group to be used for key exchange. π
β logfile
logfile(DICT) => log closure
Valid keys in the DICT argument are:
filenameβ The path to log to.classβ A list of strings defining which classes of message to log. The possible message classes aredebug-config,debug-phase,debug,info,notice,warning,error,securityandfatal.
all-debug is the union of all the debug... classes. default is equivalent to warning, error, security, fatal. verbose is equivalent to info, notice, warning, error, security, fatal. quiet is equivalent to fatal.
A log closure is a means of saving log messages. See also syslog below. π
π§ makelist
makelist(DICT) => LIST
Returns the (flattened) list of values from the dictionary, discarding the keys. β¨
π map
map(CLOSURE, INPUT...) => LIST
Applies CLOSURE to all its additional input arguments and returns the resulting list.
π₯ md5
md5 is a hash closure implementing the MD5 algorithm.
π«Ά null-netlink
null-netlink(DICT) => netlink closure
null-netlink(DICT) => pure closure
Valid keys in the DICT argument are:
nameβ String. The name for the netlink device. The default isnull-netlink.networksβ List of strings. The networks on the host side of the netlink device.remote-networksβ List of strings. Networks that may be claimed by remote sites using this netlink device.secnet-addressβ String. IP address of this netlink. Incompatible withptp-address.ptp-addressβ String. IP address of the other end of a point-to-point link. Incompatible withsecnet-address.mtuβ Number. The MTU of the netlink device. The default is1000.
If ptp-address is used then the result is a netlink closure. This can be used directly with the link key in the sites closure (see below).
If secnet-address is used then the result is a pure closure. This must be evaluated to yield a netlink closure, using a dictionary argument with the following keys:
routesβ String list. networks reachable via this tunnel, inaddress/bitsformat.optionsβ String list. It's literally a list of options, bestie:allow-routeβ let packets that arrived through this tunnel get routed down other tunnels too. Without it, only packets coming from the host itself get routed. π«softβ when the link quality hits0, yeet these routes out of the host routing table. bye routes π
mtuβ Number. The default MTU over this link. The default is inherited from the pure closure.priorityβ Number. How much this link matters. Higher values beat lower values. The default is0.
A netlink closure is a virtual IP link, and it gets handed to the link key of a site closure.
The netlink that null-netlink makes has no connection to the host at all. If you want something that actually does stuff, go look at tun and userv-ipif below, bestie. π«Ά
randomfile π²
randomfile(FILENAME[, BLOCKING]) => randomsource closure
FILENAMEβ String. Path to the random device, like/dev/urandom.BLOCKINGβ Boolean. True if this is a blocking device, false if it isn't (and false is the default). Heads up: blocking device support is not implemented, so this has to always beFalseor just... not there. π
A randomsource closure is a source of random numbers. That's the whole vibe. β¨
readfile π
readfile(PATH) => STRING
Reads the contents of the file PATH (a string) and hands it back to you as a string. Iconic, simple, no notes.
eax-serpent π
eax-serpent(DICT) => transform closure
The valid keys in the DICT argument are:
max-sequence-skewβ the biggest acceptable difference between the sequence number in a received, decrypted message and the previous one. The default is10. You might need to bump this up if your connectivity is rough.tag-length-bytesβ the length of the message authentication tag. The default is16, which means a 128-bit tag length. It must be no longer than the Serpent blocksize,16. And it has to have the same value at both ends, no cap. π₯padding-roundingβ messages get padded up to a multiple of this many bytes, which serves to obscure the exact length of messages. The default is16,capab-numβ the capability number to use when advertising this transform. The default forserpent-eaxis9.
A transform closure is a reversible means of transforming messages for transmission over a (presumably) insecure network. It's responsible for both confidentiality and integrity, so it's doing the most. π
serpent256-cbc π
serpent256-cbc(DICT) => transform closure
This transform is deprecated because its security properties are poor. Only ever specify it alongside a better transform like eax-serpent. For real, bestie. π
Valid keys in the DICT argument are:
capab-numβ as above. The default forserpent256-cbcis8.max-sequence-skewβ as above.
Note that this uses a big-endian variant of the Serpent block cipher, which is not compatible with most other Serpent implementations. iykyk.
rsa-private π
rsa-private(PATH[, CHECK]) => sigprivkey closure
PATHβ String. The path to a file containing an RSA private key in SSH format (version 1). There must be no passphrase.CHECKβ Boolean. If true (and true is the default) then it checks that the key is valid.
rsa-public π
rsa-public(KEY, MODULUS) => sigpubkey closure
KEYβ String. The public key exponent (e), in decimal.MODULUSβ String. The modulus (n), in decimal.
sha1 π
sha1 is a hash closure implementing the SHA-1 algorithm. Short king, does its one job.
site π
site(DICT) => site closure
Valid keys in the DICT argument are:
local-nameβ String. The site's name for itself.nameβ String. The name of the site's peer.linkβ A netlink closure.commβ A comm closure.resolverβ A resolver closure.randomβ A randomsource closure.local-keyβ An sigprivkey closure. The key used to prove our identity to the peer.addressβ String. The DNS name of the peer. Optional β but if it's missing, then it won't be possible to initiate new connections to the peer. So like, if you want to call them, you need their number. πportβ Number. The port to contact the peer.keyβ An sigpubkey closure. The key used to verify the peer's identity.transformβ One or more transform closures. Used to protect packets exchanged with the peer. These should all have distinctcapab-numvalues, and the samecapab-numvalue should have the same (or a compatible) meaning at both ends. The list should be in order of preference, most preferred first. (The end which sendsMSG1,MSG3ends up choosing; the ordering at the other end is irrelevant.) slay πdhβ A dh closure. The group to use in key exchange.hashβ The hash function used during setup.key-lifetimeβ Number. The maximum lifetime of a session key, in milliseconds. The default is one hour.setup-retriesβ Number. The maximum number of times a key negotiation packet will be transmitted before giving up. The default is5.setup-timeoutβ Number. The time between retransmissions of key negotiation packets, in milliseconds. The default is one second.wait-timeβ Number. The time to wait after a failed key setup before making another attempt, in milliseconds. The default is20s.renegotiate-timeβ Number. The time after which a new session key will be negotiated, if there's traffic on the link, in milliseconds. It must not be greater than thekey-lifetime. The default is 5 minutes less than the key lifetime β unless the lifetime is less than 10 minutes, in which case the default is half the lifetime.keepaliveβ Boolean. If true, then attempt to always maintain a live session key. Not implemented.log-eventsβ String list. Types of event to log for this site:unexpectedβ unexpected key setup packets (including late retransmissions).setup-initβ start of attempt to setup a session key.setup-timeoutβ failure of attempt to setup a session key, through timeout.activate-keyβ activation of a new session key.timeout-keyβ deletion of current session key through age.securityβ anything potentially suspicious. πstate-changeβ steps in the key setup protocol.packet-dropβ whenever we throw away an outgoing packet.dump-packetsβ every key setup packet we see.errorsβ failure of name resolution, internal errors.allβ everything (too much!)
A site closure defines one site to communicate with. secnet expects the (root) key site to be a list of site closures. Yes bestie, a whole list. π
sysbuffer π§Ί
sysbuffer([SIZE[, OPTIONS]]) => buffer closure
SIZEβ Number. The size of the buffer in bytes. This must be between64and131072. The default is4096.OPTIONSβ Dictionary. Optional and presently unused. (It's just sitting there. Let it sit. π )
A buffer closure is a means of buffering packets to send or that have been received.
syslog π
syslog(DICT) => log closure
Valid keys in the DICT argument are:
identβ String. The ident string to pass toopenlog(3); this value will appear in each message.facilityβ String. The facility to log as. The possible values areauthpriv,cron,daemon,kern,local0-7,lpr,mail,news,syslog,useranduucp.
See also logfile above. π
tun π£οΈ
tun(DICT) => netlink closure
tun(DICT) => pure closure
Valid keys in the DICT argument are those documented for null-netlink above, plus:
flavourβ String. The type of TUN interface to use. Possible values arelinux,bsd,streamsandguess. The default isguess.deviceβ String. The path to the TUN/TAP device file. The default is/dev/net/tunfor thelinuxflavour and/dev/tunfor the others.interfaceβ String. The interface to use. The default is to pick one automatically. This cannot be used with thestreamsflavour.local-addressβ String. IP address of the host's tunnel interface.ifconfig-pathβ String. The name of theifconfigcommand. The default is simply"ifconfig".route-pathβ String. The name of theroutecommand. The default is simply"route".ifconfig-typeβ String. The syntax expected by theifconfigcommand. Possible values arelinux,bsd,ioctl,solaris-2.5andguess. The default isguess.route-typeβ String. The syntax expected by theifconfigcommand. Possible values arelinux,bsd,ioctl,solaris-2.5andguess. The default isguess.bufferβ A buffer closure to use for packets transferred from the host to secnet. The buffer size must be at least 60 greater than the MTU.
The ifconfig-type and route-type values determine how those commands get executed. If they're set to ioctl, then low-level system calls are used directly instead of invoking the commands. spicy πΆοΈ
The netlink created by tun uses the tun device to communicate with the host kernel. That's the whole point, periodt.
udp π‘
udp(DICT) => comm closure
Valid keys in the DICT argument are:
addressβ String. The IP address to bind on. The default is0.0.0.0, i.e. "any".portβ Number. The port number to bind to. The default is0, i.e. the OS will choose one. It is suggested that any given VPN agree a common port number. (Communication is key, bestie. π«Ά)bufferβ A buffer closure. See thesysbufferclosure above.authbindβ String. The path to a helper program to bind the socket. Optional.
The program will be invoked with the address and port number as its arguments, and with the socket to bind as file descriptor 0. It should either bind the socket as requested, or exit with nonzero status.
A comm closure is a means of sending and receiving messages via a network. It does not provide confidentiality, reliablity or availability. So like, don't trust it with your secrets. π
userv-ipif π§
userv-ipif(DICT) => netlink closure
userv-ipif(DICT) => pure closure
Valid keys in the DICT argument are those documented for null-netlink above, plus:
local-addressβ String. IP address of the host's SLIP interface.userv-pathβ String. Where to finduserv(1). The default is"userv".service-userβ String. The name of the user that owns the service. The default is"root".service-nameβ String. The name of the service to request. The default is"ipif".bufferβ abufferclosure to use for packets transferred from the host tosecnet. π«Ά
Okay so the netlink that userv-ipif creates? It invokes the userv service you specified, with pipes connected to its standard input and output. And then β this is the part that's lowkey iconic β it uses SLIP to talk to the host kernel through those very pipes. π¦
πΈ FILES πΈ
/etc/secnet/secnet.confβ the configuration file, bestie. That's where everything lives. π
β¨ SEE ALSO β¨
userv(1)β go read it, it's giving essential context, no cap. π
and that's the whole page, fr fr π
it came from the secnet(8) manual, dated whenever the maintainers last touched it β we're just here, vibing in the terminal, being extremely good at Unix. slay, go configure something. πβ¨π¦
π¦ where this page comes from
- debian bookworm: secnet 0.6.7
- debian trixie: secnet 0.6.7+b1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms