ser2net.yaml(5)
πΈ ser2net.yaml β the manual page (part 1) πΈ
okay bestie, welcome to ser2net.yaml(5) from the File Formats Manual β this is the whole entire lore of the config file at /etc/ser2net/ser2net.yaml, and it's giving serial-to-network proxy configuration file. sit down, grab a snack π, we're doing this properly.
π NAME
/etc/ser2net/ser2net.yaml β the Serial to network proxy configuration file. that's it, that's the name, she's iconic π
β¨ DESCRIPTION
so like, a lil history lesson because context is everything π«Ά: ser2net used to be a program for connecting network connections to serial ports. and now? it's a program for connecting accepter gensios to connecting gensios. if you're like "gensio??" β go read gensio(5) for the details on gensios, no cap.
ser2net is configured with YAML, which is flexible and easy to use. look up yaml documentation on the internet for how that works. slay, go learn a file format π
BUT here's the plot twist π: there are two types of YAML files that ser2net can use β version 1 and version 2.
- Version 1 YAML files have more capability than version 2 files, but they are non-standard YAML β a standard YAML parser cannot read them.
ser2netwill autodetect the version based upon what it finds.
In version 2, you can have multiple documents in a file and ser2net will read all of them. YAML separates documents in a file with a single --- by itself at the beginning of a line. Though you can only have one set of defaults, defines, connections, etc. in a document, you can have multiple documents in a file to allow more than one. You might, for instance, group all the connections with a certain set of defaults into its own document. organization?? we love her π
π¦ DEFINE SPECIFICATION
YAML has the ability to create aliases that can be used elsewhere in the configuration file. These can be used for tying things together between parts of the file, or (as an extension to YAML) for string substitution. periodt.
You define an alias in version 1 with the following:
define: &aliasname alias text
This will create an alias with the given name. Then you can use it elsewhere like:
banner: *aliasname
and the banner will be "alias text". Unlike standard YAML, you can also use this inside strings using
*(aliasname)
so if you have
banner: My banner *(aliasname) is here
The banner will be "My banner alias text is here". See the YAML documentation for how spaces are handled, but as a note, use quotes if you are not sure, like:
define: &aliasname "alias text"
banner: "My banner *(aliasname) is here"
If you for some reason need "*(" in your text, use "*(*" for that.
For version 2 YAML files, the definition is:
defines:
aliasname: alias text
aliasname2: alias text 2
where you can list as many aliases as you like. In version 2, you always refer to an alias with "=" instead of "*", like:
banner: "My banner =(aliasname) is here"
and if you for some reason need "=(" in your text, use "=(=" for that.
In version 2, per standard YAML, you can only have one defines section, so they must all be together. no scattering, bestie π«Ά
π INCLUDING OTHER FILES
A YAML file may include another file at the main level, with:
include: <filename>
This filename can include globs, and all referenced files are included. These must be full yaml files, but are included in context at this point, with all the defines, connection names, etc. This can let you have individual connections in individual files to ease management. very demure, very organized π
In version 2, you can only have one include in each document for legal YAML, so if you need multiple includes you will have to have multiple documents. them's the rules π
π USING EXTERNAL FILES
You may want to store passwords and such in external files for better security. yesss protect the secrets π
- For version 1, putting
"*{filename}"in a YAML scalar will put the file's contents into the scalar at that point. If you need a"*{"in the string for some reason, use"*{*". - For version 2, use
"={filename}"instead. And"={="to include a"={"in a file.
π CONNECTION SPECIFICATION
A connection is a structure that describes how to connect an accepting gensio to a connecting gensio. the main character energy of this whole file, honestly.
A connection specification in version 1 starts with:
connection: &<alias>
<definition>
In version 2, it's specified as:
connections:
<alias>:
<definition>
In version 2, all the connections must occur together in one place. no splitting them up, she's clingy π
The <definition> of a connection is the same for version 1 and version 2:
accepter: <accepter>
timeout: <number>
enable: on|off
connector: <connector>
options:
<option name>: <option value>
<option name>: <option value>...
An <accepter> is an accepting gensio specification. When ser2net receives a connection on the accepter, it attempts to make a connection to the <connector> gensio. The alias is required β it sets the name that is used for the connection in the admin interface and for referencing from rotators. don't skip it bestie, it's load-bearing π
If the connection receives no activity in <timeout> seconds, ser2net will close the connection. Setting <timeout> to zero disables the timeout. The timeout field is optional and defaults to zero.
The timeout has some subtle workings about it π:
- Any data from the accepter port will reset the timer.
- Data sent is a little more subtle, as it doesn't mean the remote end is actually there.
ser2netattempts to look into the local queues to see if data is pending to be sent. If it detects that the other end is not accepting bytes, it considers that port "stuck" and will only consider ports that are stuck; a stuck port will not cause other ports to time out. If no port is stuck, any data transmitted will reset the timer.
The connection may be enabled or disabled with the enable. The enable field is optional and defaults to on. This is useful for temporarily disabling a port by setting enable to off and sending a SIGHUP.
β οΈ If there are users connected and you disable a port and send a SIGHUP, the users will be kicked off. π rip to them fr fr
An option is a configuration setting that doesn't have anything to do with specific gensios β they are controls for ser2net in general. The option section is optional.
See gensio(5) for a lot of information about the specific gensios available. (yes, go read it, it's the sequel β¨)
To allow a TCP connection to a serial port and ignore modem control, you can do:
connection: &toS0tcp
accepter: tcp,1234
connector: serialdev,/dev/ttyS0,local
Both accepting and connecting gensios stack, so if you want to add telnet with RFC2217 support, you can do:
connection: &toS0telnet
accepter: telnet(rfc2217),tcp,1234
connector: serialdev,/dev/ttyS0,local
If you want to accept a telnet over SCTP connection only on IPv6 localhost and connect to a telnet connection with SSL over tcp, you can do:
connection: &tomyhost
accepter: telnet,sctp,::1,1234
connector: telnet,ssl,tcp,myhost.domain.org,1234
RFC2217 support only makes sense with a serial-capable device as the connector. Also note that IPv6 is fully supported. Accepters will generally default to being both IPv4 and IPv6 unless otherwise specified. See gensio(5) for details.
And yes, SCTP is supported and is highly recommended if you can use it. Multi-homing alone is worth it. she ate π₯
You could create a secure login with telnet RFC2217 support that then connects to an IPMI sol connection. Notice how splitting the connector line is done with YAML. π
connection: &authsol
accepter: telnet(rfc2217),mux,certauth,ssl,sctp,1234
connector: ipmisol,lan -U ipmiusr -P test -p 9001
ipmiserver.domain.org,9600
options:
banner: My banner
These are some examples. For SSL and certauth, I have ignored the authentication configuration β more on that later. Using authentication is strongly recommended, it's easy now with gtlssh and if you need to use it from a program, it's easy with gensio. There is even python support. Adding support for other scripting languages shouldn't be too hard. πβ¨
π SPECIAL STRING HANDLING
Some string values, like banners, have special formatting for inserting various values. These are all prepended with \. This takes the standard "C" \x characters. here's the whole menu, no skips π
\aβ bell\bβ backspace\fβ form feed\nβ newline\rβ carriage return\tβ tab\vβ vertical tab\\β \\?β ?\'β '\"β "\nnnβ octal value fornnn\xXXβ hex value forXX\dβ The connector string (/dev/ttyS0, etc.)\oβ The name of the connection.\pβ Network port number\Bβ The serial port parameters (eg9600N81) if applicable\Y-> year\y-> day of the year (days since Jan 1)\M-> month (Jan, Feb, Mar, etc.)\m-> month (as a number)\A-> day of the week (Mon, Tue, etc.)\D-> day of the month\e-> epoc (seconds since Jan 1, 1970)\U-> microseconds in the current second\p-> local port number\I-> remote IP address (in dot format)\H-> hour (24-hour time)\h-> hour (12-hour time)\i-> minute\S-> second\q-> am/pm\P-> AM/PM
These sequences may be used to make the filename unique per open and identify which port/device the filename was for. Note that in filenames when using \d or \o, everything up to and including last / in the device name is removed, because you can't have a / in a filename. So in a filename /dev/ttyS0 would become just ttyS0. slay, path traversal said no π
π Note that in banners and other strings going out (not filenames) you must use\r\nto send a new line; this is raw handling and\nwill only go down one line, it will not return to the beginning of the line. important!! π
π«Ά CONNECTION SPECIFICATION OPTIONS
kickolduser: true|falseβ sets the port so that the previous user will be kicked off if a new user comes in. Useful if you forget to log off from someplace else a lot. (we've all been there π)timeout-on-os-queue: true|falseβ Normallyser2netonly uses its internal counts to know when to time out a connection. If a remote end OS crashes or the network fails, writes will go into the OS queue until that fills up, then writes will stop inser2net. That can take a long time.
This option modifies the behavior to take the OS queue into account. If it doesn't see the OS queue sending data out for the timeout, it will shut down.
Though this is probably a good idea in general, it is false by default to preserve old behavior since this was added later. It may switch to true by default on a major release. π keep an eye on it bestie
banner: <banner string>β displays the given banner when a client connects. It uses string handling as described in "SPECIAL STRING HANDLING" above. πsignature: <signature string>β sends RFC2217 signature on clients request. This may be an empty string.
and that's part 1 bestieβ¦ she's long but she's worth it, more coming β¨
okay bestie, we're still in the connection options and there are SO many, but every single one is here, no cap. π β¨
openstr: <openstr name string>β okay so this one sends the given string to the device on first open. It can be an empty string. It uses string handling as described in "SPECIAL STRING HANDLING" above. πclosestr: <closestr name>β sends the given string to the device on final close. It can be an empty string. It uses string handling as described in "SPECIAL STRING HANDLING" above. β¨closeon: <closeon string>β bestie, if the given string is seen coming from the connector side of the connection, close the connection. The comparison here is, for simplicity, simplistic. Complex expressions with repetitive things may not compare correctly. For instance, if your closeon string is "ababc" and your input string is "abababc", the comparison will fail because the comparison algorithm will see "ababa" and will fail on the final "a" and start over at "abc", which won't match. This shouldn't cause a problem most cases, but if it does, contact the authors and it can be improved. πaccepter-retry-time: <time in seconds>β If the accepter does not come up at startup, wait this many seconds and retry it. πconnector-retry-time: <time in seconds>β On a connect-back port, if the connector does not come up or goes down. wait this many seconds and retry it. πtrace-read: <filename>β When the acceptor is opened, open the given file and store all data read from the physical device (and thus written to the client's network/acceptor port) in the file. If the file already exists, it is appended. The file is closed when the port is closed. The filename uses string handling as described in "SPECIAL STRING HANDLING" above. πtrace-write: <filename>β Liketr, but traces data written to the connecting gensio. βοΈtrace-both: <filename>β trace both read and written data to the same file. Note that this is independent oftrandtw, so you may be tracing read, write, and both to different files. πtrace-hexdump: true|falseβ turns on/off hexdump output to all trace files. Each line in the trace file will be 8 (or less) bytes in canonical hex+ASCII format. This is useful for debugging a binary protocol. πtrace-timestamp: true|falseβ adds/removes a timestamp to all of the trace files. A timestamp is prepended to each line if hexdump is active for the trace file. A timestamped line is also recorded in the trace file when a remote client connects or disconnects from the port. β°[trace-read-|trace-write-|trace-both-]hexdump: true|falseβ turns on/off hexdump output for only one trace file. May be combined with hexdump. Order is important. π’[trace-read-|trace-write-|trace-both-]timestamp: true|falseβ adds/removes a timestamp to only one the trace files May be combined with[-]timestamp. Order is important. β³telnet-brk-on-sync: true|falseβ causes a telnet sync operation to send a break. By default data is flushed until the data mark, but no break is sent. π‘chardelay: true|falseβ enables the small wait after each character received on the connecting gensio before sending data on the accepted gensio. Normally ser2net will wait the time it takes to receive 2 serial port characters, or at least 1000us, before sending. This allows more efficient use of network resources when receiving large amounts of data, but gives reasonable interactivity. Default is true. Note that this feature is designed to balance network efficiency and interactivity. It is not designed to give guarantees of minimum chunk of data size, as task scheduling and network stacks can modify these things, too. π°οΈchardelay-scale: <number>β sets the time, measured in tenths of serial port characters, to wait after receiving from nothing from the connection before sending to the accepted gensio. So setting this to 25 will cause ser2net to wait the amount of time it takes to receive 2.5 serial port characters after receiving the last character before sending the data on to the TCP port. The default value is 20, max is 1000. This is ignored for non-serial gensios. πchardelay-min: <number>β is the same as chardelay-scale, but in microseconds. The larger of chardelay-scale and chardelay-min is used. The default value is 1000, max is 100000. π¬chardelay-max: <number>β sets the maximum delay that ser2net will wait, in microseconds, after receiving a character, before sending the data. The default value is 20000, max is 1000000. This keeps the connection working smoothly at slow speeds. π’sendon: <sendon string>β If the given string is seen coming from the connector side of the connection, sends buffered data up to and including the string. Disabled by default. As an example, this can be set to\r\nwith appropriate chardelay settings to send one line at a time. It uses string handling as described in "SPECIAL STRING HANDLING" above. See the notes on the closeon string for important information on how the comparison is done. π¨dev-to-net-bufsize: <number>β sets the size of the buffer reading from the connecting gensio and writing to the accepted gensio. π¦net-to-dev-bufsize: <number>β sets the size of the buffer reading from the accepted gensio and writing to the connecting gensio. π¦led-tx: <led-alias>β use the previously defined led to indicate serial tx traffic on this port. For version 2 this should be a YAML alias, like*led2. For version 2 just use the name, likeled2. π‘led-rx: <led-alias>β use the previously defined led to indicate serial rx traffic on this port. For version 2 this should be a YAML alias, like*led2. For version 2 just use the name, likeled2. π‘led-conn: <led-alias>β use the previously defined led to indicate as user is connected to the port. For version 2 this should be a YAML alias, like*led2. For version 2 just use the name, likeled2. π‘max-connections: <number>β set the maximum number of connections that can be made on this particular TCP port. If you make more than one connection to the same port, each ports output goes to the device, and the device output goes to all ports simultaneously. See "MULTIPLE CONNECTIONS" below for details. The default is 1. π―remaddr: <addr>[;<addr>[;...]]β specifies the allowed remote connections, where the addr is a standard address, generally in the form<ip address>,<port>. Multiple addresses can be separated by semicolons, and you can specify remaddr more than once. If your version of gensio is 3.0.3 or later, you can use subnet masks with remaddr, like:remaddr: 192.168.33.0/24,0;1234:5678:9abc:21::/64,0and it will allow connections for those entire subnets. If you set the port for an address to zero, ser2net will accept a connection from any port from the given network host. πno-con-to-acc: true|falseβ If true, do not transfer any data from the connector to the accepter. Throw any data received from the connecter away. ποΈno-acc-to-con: true|falseβ If true, do not transfer any data from the accepter to the connecter. Throw any data received from the accepter away. ποΈconnback: <connector>[;<connector>[;...]]β specifies reverse connections that will be made when data comes in on the device. When data comes in on the device side (the connection's main connector) ser2net will connect to each connback specified. No connection is made until data comes in, and normal connection timeouts apply. Note that this will use one of the connection's connections all the time. You may need to increase max-connections if you need more than one or want to accept incoming connections, too. Connect back addresses must match the format of the accepter address. So, for instance, if your accepter is"telnet,tcp,1234"your connect back address must be something like"telnet,tcp,hostname,1123". The port will send no data to any connect back unless all the connect backs are connected. A connect back port can also have connections made to it if you set the number of connections larger than the number of connect backs specified. However, those connections will receive no data from the port uness all connect backs have been established. πconnback-timeout: <time in seconds>β specifies a separate timeout for connect back ports. Normally it uses the main timeout, this lets you have a different one. Setting it to zero, like the main timeout, disables the timeout. β±οΈauthdir: <directory string>β specified the authentication directory to use for this connection. πpamauth: <service name>β Enables PAM authentication and sets the PAM service name. πallowed-users: <space separated list of names>β The users that are allowed to use this connections. This has no meaning if authentication is not enabled on the connections. If this is not set or defaulted, all users are allowed. If this is set to an empty set of users, then no users are allowed. This may be specified more than once, each one adds more users. π₯mdns: true|falseβ Enables/disables mdns support for the connection. If you set this and mdns is available, ser2net will create a service on mdns for the port. π‘mdns-interface: <num>β Sets the specific network interface to advertise the device. Defaults to -1, which means all network interfaces. π§mdns-nettype: unspec|ipv4|ipv6β Sets which network type to provide for the device advertisement. Defaults to unspec, which means do ipv4 and ipv6. πmdns-name: <string>β Sets the name in the mDNS advertisement. Defaults to the connection name. π·οΈmdns-type: <string>β Sets the type in the mDNS advertisement. Defaults to"_iostream._xxx"where xxx is either tcp, udp # # or sctp base on the gensio type. π·οΈmdns-domain: <string>β Sets the name in the mDNS advertisement. Defaults to the system setting. Don't set this unless you really know what you are doing. π·οΈmdns-host: <string>β sets the host in the mDNS advertisement. Defaults to the system setting. Don't set this unless you really know what you're doing β like, genuinely, bestie, hands off unless you're That Girl with the network configs. πmdns-txt: <string>β adds a text string to the mDNS advertisement. The string should be in the form"name=value". You can put literally anything you want in the strings. ser2net adds two default strings for you:"provider=ser2net"and"gensiostack=...", where the stack of gensios gets dropped in, like"telnet(rfc2217),tcp)". The whole idea of gensiostack is that you can just tack the address onto the end and make a connection usingstr_to_gensio(). iykyk πmdns-sysattrs: true|falseβ on Linux, adds system attributes from sysfs for USB serial ports into the mDNS txt fields. If the serial port is USB, it adds"devicetype=serialusb"and these attributes from sysfs:bInterfaceNumber,interface,idProduct,idVendor,serial,manufacturer,product. If they're not present in sysfs, they just don't get added, nbd. If the serial port is not USB, then"devicetype=serial"gets added instead. π¦
π¨ Note, and I mean this one: be very careful when using a gensiostack withstr_to_gensio(). Just blindly callingstr_to_gensio()with it could result in significant security issues, because it can passpty,stdio,trace, etc. gensios inside it. You must either validate that the stack is a safe set, or just use it for information only. You have been warned. Be careful. π
π ROTATOR
A rotator lets a single network connection connect to one of a number of connections. it's giving load-balancer-but-for-serial, and we're obsessed. β¨
A version 1 rotator specification starts with:
rotator: &<alias>
<definition>
A version 2 rotator specification starts with:
rotators:
<alias>:
<definition>
Just like connections, in version 2 you have to put all the rotators together β no scattering them around the file, bestie. π ββοΈ
The definition of a rotator is almost the same between version 1 and version 2:
accepter: <accepter>
connections: [
<connection alias>,
<connection alias>....
]
options:
<option name>: <option val>
<option name>: <option val>...
A rotator has four possible options, "authdir", "pamauth", "allowed-users", and "accepter-retry-time", both same as connections. π
For version 1, you should use YAML aliases for the connections. For version 2, just use the alias names.
Connections to the accepter will go through the set of connections and find the first unused one and use that. The next connection will start after the last connection used. Heads up though: disabled connections are still accessible through rotators. π
Note that the security of the connection is NOT used, only the security of the rotator. Like, the rotator's security is the one calling the shots here. π
π¦ SER2NET DEFAULTS
To set a default in version 1, do:
default:
name: <default name>
value: <default value>
class: <default class>
In version 2, like other things, the defaults are all in one place in a document, like:
defaults:
<name>:
value: <default value>
class: <default class>
<name2>:
value: <default value>
class: <default class>
The class is optional. If it's not there, it sets the base default for all classes, and that gets used unless it's overridden for a specific class. If the class is there, it sets the default for a specific gensio class. There's also a ser2net class that's for ser2net-specific options. π
The class is useful if you want different values for different gensio types. For instance, if you wanted all serial ports to run at 9600 baud and all IPMI SOL connections to run at 115200 baud, you could do:
default:
name: speed
value: 9600
class: serialdev
default:
name: speed
value: 115200
class: ipmisol
The value is also optional. If it's not present, a string value is set to NULL and an integer value is set to 0.
The order in the file is important β you must set a default before it's used, and you can change the value of the default. It will affect all uses following the setting. π
To delete a default value for class (so it will use the base default), for version 1 do:
delete_default:
name: <default name>,
class: <default class>
For version 2, do:
delete_defaults:
<default name>: [ <class1>, <class2>, ... ]
<default name2>: [ <class1>, <class2>, ... ]
and it will delete the defaults for the classes in the list after it.
You must supply the class, you cannot delete base defaults. sorry bestie, no base-default deletion era. π
The following default values are specific to ser2net, given with their default values:
telnet-brk-on-sync: falseβ if a telnet sync is received, send a break on the connected gensio (if applicable). By default data is flushed until the data mark, but no break is sent.kickolduser: falseβ if a new user comes in on a connection that already has a user, kick off the previous user. bye bestie πchardelay: trueβ enable a small wait after each character received on the serial port before sending data on the TCP port. Normally ser2net will wait the time it takes to receive 2 serial port characters, or at least 1000us, before sending on the TCP port. This allows more efficient use of network resources when receiving large amounts of data, but gives reasonable interactivity.chardelay-scale: 20β sets the number of serial port characters, in tenths of a character, to wait after receiving from the serial port and sending to the TCP port. So setting this to25will cause ser2net to wait the amount of time it takes to receive 2.5 serial port characters before sending the data on to the TCP port. This can range from1-1000.chardelay-min: 1000β sets the minimum delay that ser2net will wait, in microseconds. If the calculation forchardelay-scaleresults in a value smaller than this number, this number will be used instead. The default value is1000. This can range from1-100000.net-to-dev-bufsize: 64β sets the size of the buffer reading from the network port and writing to the serial device.dev-to-net-bufsize: 64β sets the size of the buffer reading from the serial device and writing to the network port.max-connections: 1β sets the maximum number of connections that can be made on this particular TCP port. If you make more than one connection to the same port, each port's output goes to the device, and the device output goes to all ports simultaneously. See "MULTIPLE CONNECTIONS" below for details.remaddr: [!]<addr>[;[!]<addr>[;...]]β specifies the allowed remote connections, where theaddris a standard address in the form (see "network port" above). Multiple addresses can be separated by semicolons, and you can specifyremaddrmore than once. If you set the port for an address to zero, ser2net will accept a connection from any port from the given network host. If a"!"is given at the beginning of the address, the address is a "connect back" address. If a connect back address is specified, one of the network connections (seemax-connections) is reserved for that address. If data comes in on the device, ser2net will attempt to connect to the address. This works on TCP and UDP. π₯authdir: /usr/share/ser2net/authβ the authentication directory for ser2net. See "AUTHENTICATION" for more details.authdir-admin: /etc/ser2net/authβ the authentication directory for ser2net for admin connections. See "ADMIN_CONNECTIONS" for more details.pamauth: <NULL>β the PAM service name for ser2net PAM authentication (<NULL>for disabled).pamauth-admin: <NULL>β the PAM service name for ser2net admin connection PAM authentication (<NULL>for disabled). See "ADMIN_CONNECTIONS" for more details.mdns-interface: -1β the default mDNS interface.mdns-type: <NULL>β the default mDNS type.mdns-domain: <NULL>β the default mDNS domain.mdns-host: <NULL>β the default mDNS host.
π ADMIN CONNECTIONS
There's an admin accepter that you can define for ser2net, and it lets you log in, look at status, and change some things. See "ADMIN INTERFACE" in ser2net(8) for the deets on how to use it. The format is:
admin: [&<name>]
accepter: <accepter>
options:
<option name>: <option value>
<option name>: <option value>...
The following authentications options available are "authdir-admin", which sets the authentication directory for the admin port, and "pamauth-admin", which sets the PAM service name and enables PAM authentication. Both are different than "authdir" resp. "pamauth" for connections, though you can set it to the same value. π
In addition, the same mdns option are available for admin ports as are available for connections. And you can set an optional alias that will also set the mDNS name.
Like connections, default mdns options work for "mdns-interface", "mdns-type", "mdns-domain", and "mdns-host". Unlike connections, the "mdns" boolean does not come from the default β you must specify it as an admin option to turn on mdns for the admin port. This is to allow it to be specified separately and maintain backwards compatibility. π«Ά
π‘ LEDS π‘
okay bestie, ser2net can flash LEDs when your serial line is doing stuff β¨. Actual blinkenlights. So if you want an LED in version 1, you do:
led: &<alias>
driver: sysfs
options:
<option name>: <option value>
<option name>: <option value>
and in version 2 it's giving nested-map energy instead:
leds:
<alias>:
driver: sysfs
options:
<option name>: <option value>
<option name>: <option value>
<alias>:
driver: sysfs
options:
<option name>: <option value>
<option name>: <option value>
The only driver supported is sysfs. No others, don't come for me. The options you get are:
device: <sysfs device name>β this is the name of the LED over in/sys/class/led. heads up: these names generally have":"in them, so you're gonna need to wrap the whole thing in quotes. This one is required, no skipping π .duration: <time in ms>β how long, in milliseconds, the LED flashes for. Defaults to10.state: <number>β the value you set the LED to in order to enable it. Defaults to1, but ngl you might need a different value depending on your setup.mode: transient | solidβ sets the led mode.transient= flash on a bit when triggered,solid= a simple on-off vibe. Generally you'd use a transient one for I/O activity,led-rxandled-tx, and a solid one for monitoring whether a connection is active or not,led-conn.
You reference the LED by alias in the connection options section, so go peek at that for the deets π. And bestie, make sure you've done modprobe ledtrig-transient or the triggers will not work β fr fr, they require the transient trigger.
Also you probably need root access to touch LED settings. sorry π«Ά
β¨ FILENAME, BANNER, AND STRING FORMATTING β¨
NOTE: yaml has it's own quoting mechanism, see below for more details.
Filenames, banners, open/close strings, closeon strings, and sendon strings can all contain normal "C" escape sequences, plus a whole pile of other escape sequences too. Look at all these:
\a - bell
\b - backspace
\f - form feed
\n - newline
\r - carriage return
\t - tab
\v - vertical tab
\\ - \
\? - ?
\' - '
\" - "
\nnn - octal value for nnn
\xXX - hex value for XX
\d - The connecting gensio string (serialdev,/dev/ttyS0, etc.)
\o - The device as specified on the config line (before DEVICE
substitution)
\N - The port name
\p - The accepter string
\B - The serial port parameters (eg 9600N81)
\Y -> year
\y -> day of the year (days since Jan 1)
\M -> month (Jan, Feb, Mar, etc.)
\m -> month (as a number)
\A -> day of the week (Mon, Tue, etc.)
\D -> day of the month
\e -> epoc (seconds since Jan 1, 1970)
\U -> microseconds in the current second
\p -> local port number
\I -> remote address of the accepter gensio
\H -> hour (24-hour time)
\h -> hour (12-hour time)
\i -> minute
\S -> second
\q -> am/pm
\P -> AM/PM
(yes, \p shows up twice with two different meanings, that's not me being messy, that's just the lore π)
In addition, for backwards compatibility because filenames and banners used to have different formatting, \s is the serial port parameters if in a banner and seconds if in a filename. Use of this is discouraged as it may change in the future. Consider yourself warned, babe.
These sequences may be used to make the filename unique per open and identify which port/device the filename was for. Note that in filenames when using \d or \o, everything up to and including last / in the device name is removed, because you can't have a / in a filename. So in a filename /dev/ttyS0 would become just ttyS0. Iconic little transformation honestly.
πΈ HANDLING QUOTING AND STRING FORMATTING πΈ
yaml will process "\" escape sequences in double quotes, so use of double quotes is note recommended for the above. If you put the values in single quotes, yaml will not process them and instead pass them through where they can be processed by ser2net. That's the move, bestie.
π SPACES, QUOTING AND PUTTING SPACES IN STRINGS π
YAML and the accepter/connector processing interact when dealing with quoting, and the way they interact is honestly a little bit of a situationship. By default, YAML ignores the number of spaces between elements separated by spaces. Lines that are indented after an element are considered a continuation of the element, so something like:
connector: serialdev,/dev/ttyUSB0,
9600n81
local nobreak
rtscts
is the same as
connector: serialdev,/dev/ttyUSB0, 9600n81 local nobreak rtscts
YAML has it's own standard quoting mechanisms, so if you do:
connector: "serialdev,/dev/ttyUSB0,9600n81 local"
the two spaces before "local" will be preserved when passed to the connector processing (though in this case it won't matter because the connector processing will ignore the extra spaces).
If you need a significant space, say in a filename passed to a key, You cannot do:
accepter: ssl(CA=/etc/ser2net/my CA/),tcp,3000
because the accepter processing will split the arguments at the space and won't recognize what "CA/" is. You also cannot do:
accepter: ssl(CA="/etc/ser2net/my CA/"),tcp,3000
because YAML will remove the quotes, this is functionally equivalent to the previous example. And
accepter: ssl(CA="/etc/ser2net/my\ CA/"),tcp,3000
also will not work, inside of double quotes YAML will convert "\ " to a space. Tragic. But bestie you have a couple of options π«Ά. You can do:
accepter: ssl(CA=/etc/ser2net/my\ CA/),tcp,3000
or
accepter: ssl(CA='/etc/ser2net/my\ CA/'),tcp,3000
because outside of quotes YAML will not process the "\ " and it will not process it in single quotes. Or if you have a lot of spaces or colons, too, you can do:
accepter: ssl(CA="\"/etc/ser2net/my CA/\""),tcp,3000
because inside the outside quotes YAML will convert the '\"' into a '"' and pass it on to the accepter processing which will interpret the quotes as you would expect. Nested quote inception. ate π
π UDP π
UDP handling is a bit different than you might imagine, because it's hard for ser2net to know where to send the data to. To handle this, UDP ports still have the concept of a "connection". If a UDP port is not connected, then if it receives a packet the remote address for that packet is set to the remote end of the "connection". It will do all the normal new connection operations. ser2net will accept new connections up to "max-connections" then ignore packets from other addresses until a disconnect occurs.
Unfortunately, there is no easy way to know when to disconnect π. You have two basic options:
- Set a timeout, if the remote end isn't heard from before the timeout, then the port is disconnected and something else can connect. This means anything that is using the port must periodically send a packet (empty is fine) to ser2net to keep the connection alive.
- Use the
kickolduseroption on the port, any new connection that comes in will replace the previous connection.
Note that UDP ports handle multiple connections just like TCP ports, so you can have multiple UDP listeners. slay.
You also have a third option π. If you set a remote address (remaddr) with a non-zero port and a connect back port (see discussion on remote addresses above), ser2net will take one of the connections and assign it to that port permanently. This is called a fixed remote address. All the traffic from the device will go to that port. Every fixed remote address on a UDP port has to have a corresponding connection, so if you have 3 fixed remote addresses, you must have at least 3 connections. do the math, bestie β¨
π₯ MULTIPLE CONNECTIONS π₯
As mentioned earlier, you can set max-connections=<n> on a port to allow more than one connection at a time to the same serial port. These connections will share all the settings. You cannot have two separate TCP ports connect to the same port at the same time. periodt.
This has some significant interactions with other features:
- flow control is not exactly a feature, but more an interaction between the different connections. If a TCP port stops receiving data from ser2net, all TCP ports connected will be flow-controlled. This means a single TCP connection can stop all the others. one diva can take down the whole group chat, iykyk π
closeonwill close all connections when the closeon sequence is seen.openstris only sent when the port is unconnected and the first connections is made.closestris only sent when the last port disconnects and there are no more connections to the port.- Any monitor (
"monitor start"from a control connections) will catch input from all network connections. kickolduserwill kick off an existing connection if a connection comes in on a port that already has a maximum number of connections. The connection kicked off is arbitrarily chosen and the algorithm is subject to change. so don't get attached π- tracing will trace data from all network connections.
rfc2217(remote telnet serial control) will change the connection settings on the device and will be accepted from any network connection.reconfigon SIGHUP Seeser2net(8)"SIGHUP"section for details.- ROTATOR will only choose a port if there are no connections at all on the port. Note that the use of a rotator with a port with
max-connections > 1will result in undefined behavior. yeah. don't do that one. timeoutwill be per TCP port and will only disconnect that TCP port on a timeout.telnet_brk_on_syncwill send a break for any TCP port that does a sync.showportin the admin interface will show all possible connections, so if you saymax-connections=3you will get three entries.showshortportin the admin interface will only show the first live connection, or if no connection is present it will show whatever the first one was the last time a connection was present.
π AUTHENTICATION AND ENCRYPTION
okay bestie, this is the security chapter and it is a lot, but stay with me because it's actually so good once it clicks. β¨
𧦠TCP WRAPPERS
ser2net uses the tcp wrappers interface to do host-based security. Peep hosts_access(5) for the whole file-setup situation. π
And listen β there are two daemons in play here:
"ser2net"β this one's for the data ports"ser2net-control"β and this one's for the control ports
π ENCRYPTION
ser2net does SSL encryption via the ssl gensio. To turn it on, use an accepter like this:
telnet,ssl,tcp,1234
Then you can connect with gensiot:
gensiot telnet,ssl,<server>,1234
or you can install telnet-ssl and go:
telnet -z ssl,secure <server> 1234
The SSL connection gets made using the keys you provide. In this example ser2net is using the default keys (they're set in the default β see below, it's giving "check the defaults"). You can also set them yourself with (key=<keyfile>,cert=<certfile>) placed after ssl up there π, or just modify the defaults. Whatever vibes.
π¨ If you do not have genuine certificates from a certificate authority, the connection will fail due to certificate failure. no cap.
Getting certificates that way is so inconvenient, so there's another way. You can do:
gtlssh-keygen --keydir /etc/ser2net --commonname
"`hostname`-ser2net" serverkey ser2net
to generate the default keys in /etc/ser2net (or wherever, bestie, you do you). The certificate/key will be named /etc/ser2net/ser2net.crt|key.
β οΈ NOTE: If you compile ser2net yourself, by default autoconf sets the system configuration directory (normally/etc) as/usr/etc. This is a major annoyance with autoconf. So if you don't change it, you would need/usr/etcabove where it says/etc. However, generally the right way to do this is to add"--sysconfdir=/etc"to the configure command line when you configure ser2net. If a distro has compiled ser2net for you, that should have done that by default, so no worries in that case. π«Ά
Then copy ser2net.crt over to the user system and provide it to connection commands, like:
gensiot telnet,ssl(CA=ser2net.crt),<server>,1234
or
telnet -z ssl,secure,cacert=ser2net.crt 1234
Then you will have an encrypted connection. π Just make sure your certificates are valid, periodt.
Note that the "-ser2net" at the end of the key is important because it makes the subject name of the certificate more unique. You can really put anything you want for what you provide to keygen, as long as you rename it properly. That will be the subject name of the certificate. π
π AUTHENTICATION WITH SSL
ser2net provides a way to authenticate with SSL. It's not the greatest, but it does work. (iconic honesty honestly.) You must enable clientauth on ssl:
telnet,ssl(clientauth),tcp,1234
or set it in the default. Then you must create a certificate with the username as the common name. You can do this with:
gtlssh-keygen --keydir outdir --commonname username keygen
keyname
which will generate keyname.crt and keyname.key in outdir. Then put keyname.crt in ser2net's <authdir>/username/allowed_certs. By default <authdir> is /usr/share/ser2net/auth, but you can change that with the authdir default in the ser2net config file, or by setting authdir on individual connections (in case you want different ones for different ports β very main character of you). You then must rehash the allowed_certs directory:
gtlssh-keygen rehash <authdir>/username/allowed_certs
Then restart/reload ser2net and use one of these very long lines to telnet into it:
gensiot
telnet,ssl(CA=ser2net.crt,cert=username.crt,key=username.key),<server>,1234
telnet -z
ssl,secure,cacert=ser2net.crt,cert=username.crt,key=username.key
server 1234
ποΈ AUTHENTICATION WITH CERTAUTH (GTLSSH)
All of the above is a big pain. π Fortunately there is an easier way. gtlssh is a ssh-like program, but it runs over TLS and it implements a ssh-like authentication protocol using the certauth gensio.
ser2net supports this authentication system running on top of the ssl and certauth gensios. Those gensios provide the framework for handling authentication, ser2net itself controls it.
This uses the same authdir and allowed keys directory as before, and still requires a server certificate, but the self-signed one generated with gtlssh-keygen works fine without doing anything special. Add certauth to the port line:
telnet,mux,certauth,ssl,tcp,1234
and make sure clientauth is disabled for ssl (or ssl will still attempt to authenticate the client). Disabled is the default but in case you changed, the default... π
The mux entry is because gtlssh uses the mux gensio to allow multiple channels on the same session. It wasn't there with older (pre 1.2) versions of gtlssh, but is required for newer ones. gtlssh also has a --nomux option, just in case. π
The gtlssh program does its own certificate handling. Look at the gtlssh man page for detail on that. Take the certificate for gtlssh and put it in the authdir/username/allowed_certs directory and reshash it as before. gtlssh will not use the common name provided in the certificate, instead it uses a username provided by gtlssh. Then connect with gtlssh:
gtlssh --nosctp --telnet username@server 1234
The --nosctp thing keeps gtlssh from trying sctp, which will fail because we put tcp in the port line. You could use sctp there and get all its advantages for free! Then --nosctp would no longer be required to avoid the nagging. β¨
The username is optional if it's the same as your current user. If you have not connected to that server/port before, gtlssh will ask you to verify it, much like ssh does. If certificates, IP address, etc. change, gtlssh will tell you about it. π¦
If you do not want to use a certificate (certificates are certainly preferred, but may not always be workable) you can use a password login, too. You must set enable-password in the certauth gensio options for passwords to work. When you connect with gtlssh, if certificate validate fails, you will be prompted for the password. Password authentication can be performed in two different ways. Both are mutually exclusive, depending on whether pamauth is set or not:
- To authenticate using the PAM library, set the PAM service name via the
pamauthoption. - Put a password in
authdir/username/password. If it matches the first line in the password file andpamauthis not set, then authentication will succeed.
π AUTHENTICATION AND ROTATORS
Rotators are a special case. BE CAREFUL. A rotator has its own authentication. If you set up authentication on a port that is part of a rotator, that port's authentication is not used. Only the rotator's authentication is used. periodt. π¨
π ENCRYPTION, AUTHENTICATION, AND DEFAULT CERTIFICATES
ser2net expects default certificates and public keys in /etc/ser2net, and these are set as gensio defaults. This means that any outgoing connection from ser2net, whether in a connector or in a connback, will use these keys. If they aren't there, or have expired, or something β you will get confusing errors about not being able to open the certificates. π
To solve this, you can disable the certificates by adding "cert=" to the gensio specification for ssl and certauth on outgoing connections. This will disable the certificates for the specific gensio, and is probably what you want. If you are making connections and authenticating to the remote server, the default certificate and private key are probably not what you want, either. π
π‘ SIGNALS
SIGHUPβ If ser2net receives aSIGHUP, it will reread its configuration file and make the appropriate changes. If an inuse port is changed or deleted, the actual change will not occur until the port is disconnected. (so patient of it honestly π§)
π ERRORS
Almost all error output goes to syslog, not standard output. iykyk β go check your logs, bestie.
π FILES
/etc/ser2net/ser2net.yaml/etc/ser2net/ser2net.key/etc/ser2net/ser2net.crt/usr/share/ser2net
π SEE ALSO
ser2net(8) telnet(1), hosts_access(5), gensio(5), gtlssh(1), gtlssh-keygen(1)
π KNOWN PROBLEMS
If they were known, they would be fixed :). (the way that is the most iconic thing anyone has ever written in a manpage π )
π AUTHOR
Corey Minyard <minyard@acm.org>
and that's the whole page bestie!! πβ¨ this was ser2net.yaml(5) β the serial to network proxy configur... page, from 06/02/01. go forth and encrypt, authenticate, and slay ππ¦π
π¦ where this page comes from
- arch rolling: ser2net 4.6.8-1 Β· GPL
- fedora 43: ser2net 4.6.8-1.fc43 Β· GPL-2.0-only
- fedora 44: ser2net 4.6.8-1.fc44 Β· GPL-2.0-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms