.Dd July 16, 2023 .Dt POUNCE 1 .Os . .Sh NAME .Nm pounce .Nd IRC bouncer . .Sh SYNOPSIS .Nm .Op Fl LNTev .Op Fl A Ar local-ca .Op Fl C Ar local-cert .Op Fl H Ar local-host .Op Fl K Ar local-priv .Op Fl P Ar local-port .Op Fl Q Ar queue-interval .Op Fl R Ar blind-req .Op Fl S Ar bind .Op Fl U Ar local-path .Op Fl W Ar local-pass .Op Fl a Ar sasl-plain .Op Fl c Ar client-cert .Op Fl f Ar save .Op Fl h Ar host .Op Fl j Ar join .Op Fl k Ar client-priv .Op Fl m Ar mode .Op Fl n Ar nick .Op Fl p Ar port .Op Fl q Ar quit .Op Fl r Ar real .Op Fl t Ar trust .Op Fl s Ar size .Op Fl u Ar user .Op Fl w Ar pass .Op Fl y Ar away .Op Ar config ... . .Nm .Fl o .Op Fl S Ar bind .Op Fl h Ar host .Op Fl p Ar port .Op Ar config ... . .Nm .Op Fl A Ar ca .Fl g Ar cert . .Nm .Fl x . .Sh DESCRIPTION The .Nm program is a multi-client, TLS-only IRC bouncer. It maintains a persistent connection to an IRC server while allowing clients to connect and disconnect, receiving messages that were missed upon reconnection. Clients must uniquely identify themselves to .Nm by their IRC username (not nickname). The IRCv3 .Sy server-time extension is used to indicate when messages were originally received. See .Sx Client Configuration for details. . .Pp The local server portion of .Nm requires a TLS certificate, which can be obtained for example by an ACME client such as .Xr acme-client 8 . The private key must be made readable by the user running .Nm . . .Pp One instance of .Nm must be configured for each IRC network. Instances of .Nm must either use different local ports with .Cm local-port or different local host names with .Cm local-host and .Cm local-path to be dispatched from the same port by .Xr calico 1 . . .Pp Client connections are not accepted until successful login to the server. If the server connection is lost, the .Nm process exits. . .Pp Options can be loaded from files listed on the command line. Files are searched for in .Pa $XDG_CONFIG_DIRS/pounce .Po usually .Pa ~/.config/pounce .Pc unless the path starts with .Ql / , .Ql \&./ or .Ql \&../ . Certificate and private key paths are searched for in the same manner. Files and flags listed later on the command line take precedence over those listed earlier. . .Pp Each option is placed on a line, and lines beginning with .Ql # are ignored. The options are listed below following their corresponding flags. . .Ss Local Server Options .Bl -tag -width Ds .It Fl A Ar path | Cm local-ca No = Ar path Require clients to authenticate using a TLS client certificate either contained in or signed by a certificate in the file loaded from .Ar path . The file is reloaded when the .Dv SIGUSR1 signal is received. See .Sx Generating Client Certificates . If .Cm local-pass is also set, clients may instead authenticate with a server password. . .It Fl C Ar path | Cm local-cert No = Ar path Load TLS certificate from .Ar path . The file is reloaded when the .Dv SIGUSR1 signal is received. The default path is .Ar host Ns .pem , where .Ar host is set by .Cm local-host . . .It Fl H Ar host | Cm local-host No = Ar host Bind to .Ar host . The default host is localhost. . .It Fl K Ar path | Cm local-priv No = Ar path Load TLS private key from .Ar path . The file is reloaded when the .Dv SIGUSR1 signal is received. The default path is .Ar host Ns .key , where .Ar host is set by .Cm local-host . . .It Fl L | Cm palaver Advertise the .Sy palaverapp.com IRCv3 vendor-specific capability to clients. This option only enables the capability; push notifications must be provided by the .Xr pounce-palaver 1 special-purpose client. . .It Fl P Ar port | Cm local-port No = Ar port Bind to .Ar port . The default port is 6697. . .It Fl T | Cm no-sts Do not advertise a strict transport security (STS) policy to clients. . .It Fl U Ar path | Cm local-path No = Ar path Bind to a UNIX-domain socket at .Ar path . Clients are only accepted as dispatched by .Xr calico 1 . If .Ar path is a directory, the .Ar host set by .Cm local-host is appended to it. This option takes precedence over .Cm local-host and .Cm local-port . . .It Fl W Ar pass | Cm local-pass No = Ar pass Require the server password .Ar pass for clients to connect. The .Ar pass string must be hashed using .Fl x . If .Cm local-ca is also set, clients may instead authenticate using a TLS client certificate. . .It Fl f Ar path | Cm save No = Ar path Save and load the contents of the buffer from .Ar path in .Pa $XDG_DATA_DIRS/pounce , usually .Pa ~/.local/share/pounce , or an absolute or relative path if .Ar path starts with .Ql / , .Ql \&./ or .Ql \&../ . The file is truncated after loading. . .It Fl s Ar size | Cm size No = Ar size Set the number of messages contained in the buffer to .Ar size . This sets the maximum number of recent messages which can be relayed to a reconnecting client. The size must be a power of two. The default size is 4096. .El . .Ss Remote Server Options .Bl -tag -width Ds .It Fl N | Cm no-names Do not request .Ql NAMES for each channel when a client connects. This avoids already connected clients receiving unsolicited responses but prevents new clients from populating user lists. . .It Fl Q Ar ms | Cm queue-interval No = Ar ms Set the server send queue interval in milliseconds. The queue is used to send automated messages from .Nm to the server. Messages from clients are sent to the server directly. The default interval is 200 milliseconds. . .It Fl R Ar caps | Cm blind-req No = Ar caps Blindly request the IRCv3 capabilities .Ar caps , which must be supported by .Nm . This can be used to enable hidden capabilities, such as .Sy userhost-in-names on some networks. . .It Fl S Ar host | Cm bind No = Ar host Bind to source address .Ar host when connecting to the server. To connect from any address over IPv4 only, use 0.0.0.0. To connect from any address over IPv6 only, use ::. . .It Fl a Ar user : Ns Ar pass | Cm sasl-plain No = Ar user : Ns Ar pass Authenticate as .Ar user with .Ar pass using SASL PLAIN. Since this method requires the account password in plaintext, it is recommended to use CertFP instead with .Cm sasl-external . . .It Fl c Ar path | Cm client-cert No = Ar path Load the TLS client certificate from .Ar path . If the private key is in a separate file, it is loaded with .Cm client-priv . With .Cm sasl-external , authenticate using SASL EXTERNAL. Certificates can be generated with .Fl g . . .It Fl e | Cm sasl-external Authenticate using SASL EXTERNAL, also known as CertFP. The TLS client certificate is loaded with .Cm client-cert . See .Sx Configuring CertFP . . .It Fl h Ar host | Cm host No = Ar host Connect to .Ar host . . .It Fl j Ar channels Oo Ar keys Oc | Cm join No = Ar channels Op Ar keys Join the comma-separated list of .Ar channels with the optional comma-separated list of channel .Ar keys . . .It Fl k Ar path | Cm client-priv No = Ar path Load the TLS client private key from .Ar path . . .It Fl m Ar mode | Cm mode No = Ar mode Set the user .Ar mode . . .It Fl n Ar nick | Cm nick No = Ar nick Set nickname to .Ar nick . The default nickname is the user's name. . .It Fl p Ar port | Cm port No = Ar port Connect to .Ar port . The default port is 6697. . .It Fl q Ar mesg | Cm quit No = Ar mesg Quit with message .Ar mesg when shutting down. . .It Fl r Ar real | Cm real No = Ar real Set realname to .Ar real . The default realname is the same as the nickname. . .It Fl t Ar path | Cm trust No = Ar path Trust the certificate loaded from .Ar path . Server name verification is disabled. See .Sx Connecting to Servers with Self-signed Certificates . . .It Fl u Ar user | Cm user No = Ar user Set username to .Ar user . The default username is the same as the nickname. . .It Fl w Ar pass | Cm pass No = Ar pass Log in with the server password .Ar pass . . .It Fl y Ar mesg | Cm away No = Ar mesg Set away status to .Ar mesg when no clients are connected and no other away status has been set. .El . .Ss Other Options .Bl -tag -width Ds .It Fl g Ar path Generate a TLS client certificate using .Xr openssl 1 and write it to .Ar path . The certificate is signed by the certificate authority if .Fl A is set, otherwise it is self-signed. . .It Fl o Print the server certificate chain to standard output in PEM format and exit. . .It Fl v | Cm verbose Log IRC messages to standard output: .Pp .Bl -tag -width "<<" -compact .It << from .Nm to the server .It >> from the server to .Nm .It -> from clients to .Nm .It <- from .Nm to clients .El . .It Fl x Prompt for a password and output a hash for use with .Cm local-pass . .El . .Ss Client Configuration Clients should be configured to connect to the host and port set by .Cm local-host and .Cm local-port , with TLS or SSL enabled. If .Cm local-pass is used, clients must send a server password. If .Cm local-ca is used, clients must connect with a client certificate and may request SASL EXTERNAL. If both are used, clients may authenticate with either method. . .Pp Clients must register with unique usernames (not nicknames), for example the name of the client software or location from which it is connecting. New clients with the same username are assumed to be reconnections and will cause previous connections to stop receiving messages. The nickname and real name sent by clients are ignored. . .Pp Normally a client sending .Ic QUIT will simply be disconnected from .Nm . If, however, the quit message starts with the keyword .Sy $pounce , .Nm itself will quit. The remainder of the message following the keyword will be used as .Nm Ap s quit message, or the default set by .Cm quit if there isn't any. . .Pp Clients which request the .Sy causal.agency/passive capability or with usernames beginning with hyphen .Ql - are considered passive and do not affect automatic away status. . .Pp Pass-through of the following IRCv3 capabilities is supported: .Sy account-notify , .Sy account-tag , .Sy away-notify , .Sy batch , .Sy cap-notify , .Sy chghost , .Sy echo-message , .Sy extended-join , .Sy extended-monitor , .Sy invite-notify , .Sy labeled-response , .Sy message-tags , .Sy multi-prefix , .Sy server-time , .Sy setname , .Sy userhost-in-names . . .Pp Private messages and notices sent to the user's own nickname are relayed only to other clients, not to the server. . .Ss Generating Client Certificates .Bl -enum .It Generate self-signed client certificates and private keys: .Bd -literal -offset indent $ pounce -g client1.pem $ pounce -g client2.pem .Ed .It Concatenate the certificate public keys into a CA file: .Bd -literal -offset indent $ openssl x509 -subject -in client1.pem \e >> ~/.config/pounce/auth.pem $ openssl x509 -subject -in client2.pem \e >> ~/.config/pounce/auth.pem .Ed .It Configure .Nm to verify client certificates against the CA file: .Bd -literal -offset indent local-ca = auth.pem # or: $ pounce -A auth.pem .Ed .El . .Pp Alternatively, client certificates can be signed by a generated certificate authority: . .Bl -enum .It Generate a self-signed certificate authority: .Bd -literal -offset indent $ pounce -g auth.pem .Ed .It Generate and sign client certificates using the CA: .Bd -literal -offset indent $ pounce -A auth.pem -g client1.pem $ pounce -A auth.pem -g client2.pem .Ed .It Since only the public key is needed for certificate verification, extract it from the CA: .Bd -literal -offset indent $ openssl x509 -in auth.pem -out ~/.config/pounce/auth.crt .Ed .It Configure .Nm to verify client certificates against the CA: .Bd -literal -offset indent local-ca = auth.crt # or: $ pounce -A auth.crt .Ed .El . .Ss Configuring CertFP .Bl -enum .It Generate a new TLS client certificate: .Bd -literal -offset indent $ pounce -g ~/.config/pounce/example.pem .Ed .It Connect to the server using the certificate: .Bd -literal -offset indent client-cert = example.pem # or: $ pounce -c example.pem .Ed .It Identify with services or use .Cm sasl-plain , then add the certificate fingerprint to your account: .Bd -literal -offset indent /msg NickServ CERT ADD .Ed .It Enable SASL EXTERNAL to require successful authentication when connecting: .Bd -literal -offset indent client-cert = example.pem sasl-external # or: $ pounce -e -c example.pem .Ed .El . .Ss Connecting to Servers with Self-signed Certificates .Bl -enum .It Connect to the server and write its certificate to a file: .Bd -literal -offset indent $ pounce -o -h irc.example.org > ~/.config/pounce/example.pem .Ed .It Configure .Nm to trust the certificate: .Bd -literal -offset indent trust = example.pem # or: $ pounce -t example.pem .Ed .El . .Sh ENVIRONMENT .Bl -tag -width Ds .It Ev USER The default nickname. .El . .Sh FILES .Bl -tag -width Ds .It Pa $XDG_CONFIG_DIRS/pounce Configuration files, certificates and private keys are searched for first in .Ev $XDG_CONFIG_HOME , usually .Pa ~/.config , followed by the colon-separated list of paths .Ev $XDG_CONFIG_DIRS , usually .Pa /etc/xdg . .It Pa ~/.config/pounce The most likely location of configuration files. . .It Pa $XDG_DATA_DIRS/pounce Save files are searched for first in .Ev $XDG_DATA_HOME , usually .Pa ~/.local/share , followed by the colon-separated list of paths .Ev $XDG_DATA_DIRS , usually .Pa /usr/local/share:/usr/share . New save files are created in .Ev $XDG_DATA_HOME . .It Pa ~/.local/share/pounce The most likely location of save files. .El . .Sh EXAMPLES Start .Nm : .Bd -literal -offset indent $ pounce -H irc.example.org -h irc.tilde.chat -j '#ascii.town' .Ed .Pp Write an equivalent configuration file to .Pa ~/.config/pounce/tilde.conf : .Bd -literal -offset indent local-host = irc.example.org host = irc.tilde.chat join = #ascii.town .Ed .Pp Load the configuration file: .Bd -literal -offset indent $ pounce tilde.conf .Ed . .Pp Add a certificate to .Xr acme-client.conf 5 : .Bd -literal -offset indent domain irc.example.org { domain key "/home/user/.config/pounce/irc.example.org.key" domain full chain certificate \e "/home/user/.config/pounce/irc.example.org.pem" sign with letsencrypt } .Ed .Pp Obtain the certificate and make the private key readable by .Nm : .Bd -literal -offset indent # acme-client irc.example.org # chown user /home/user/.config/pounce/irc.example.org.key .Ed .Pp Renew and reload the certificate with a .Xr cron 8 job: .Bd -literal -offset indent ~ * * * * acme-client irc.example.org && pkill -USR1 pounce .Ed . .Sh DIAGNOSTICS Upon receiving the .Dv SIGINFO signal, .Nm prints the current producer position and the positions of each consumer identified by username. Following each consumer position is the number by which it trails the producer. On systems lacking .Dv SIGINFO , .Dv SIGUSR2 is used. . .Pp If a client reconnects after having missed more messages than the size of the buffer, .Nm will print a warning: .Bd -ragged -offset indent consumer .Em name dropped .Em n messages .Ed .Pp The size of the buffer can be adjusted with .Fl s . . .Sh SEE ALSO .Xr calico 1 . .Sh STANDARDS .Bl -item .It .Rs .%A Waldo Bastian .%A Ryan Lortie .%A Lennart Poettering .%T XDG Base Directory Specification .%U https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html .%D November 24, 2010 .Re .It .Rs .%A Kyle Fuller .%A St\('ephan Kochen .%A Alexey Sokolov .%A James Wheare .%T server-time Extension .%I IRCv3 Working Group .%U https://ircv3.net/specs/extensions/server-time .Re .It .Rs .%A Lee Hardy .%A Perry Lorier .%A Kevin L. Mitchell .%A Attila Molnar .%A Daniel Oakley .%A William Pitcock .%A James Wheare .%T IRCv3 Client Capability Negotiation .%I IRCv3 Working Group .%U https://ircv3.net/specs/core/capability-negotiation .Re .It .Rs .%A S. Josefsson .%T The Base16, Base32, and Base64 Data Encodings .%I IETF .%R RFC 4648 .%U https://tools.ietf.org/html/rfc4648 .%D October 2006 .Re .It .Rs .%A C. Kalt .%T Internet Relay Chat: Client Protocol .%I IETF .%R RFC 2812 .%U https://tools.ietf.org/html/rfc2812 .%D April 2000 .Re .It .Rs .%A Attila Molnar .%A James Wheare .%T IRCv3 Strict Transport Security .%I IRCv3 Working Group .%U https://ircv3.net/specs/extensions/sts .Re .It .Rs .%A Attila Molnar .%A William Pitcock .%T IRCv3.2 SASL Authentication .%I IRCv3 Working Group .%U https://ircv3.net/specs/extensions/sasl-3.2 .Re .It .Rs .%A K. Zeilenga, Ed. .%T The PLAIN Simple Authentication and Security Layer (SASL) Mechanism .%I IETF .%R RFC 4616 .%U https://tools.ietf.org/html/rfc4616 .%D August 2006 .Re .El . .Ss Extensions The .Sy causal.agency/consumer vendor-specific IRCv3 capability enables the .Sy causal.agency/pos message tag. The value of this tag is a 64-bit unsigned integer indicating the consumer position of the client after receiving each message, e.g.\& .Ql @causal.agency/pos=42069 . This capability may be requested with the value of the last .Sy causal.agency/pos tag received by the client, e.g.\& .Ql CAP REQ causal.agency/consumer=42069 , setting its consumer position. By persisting this value across connections, a client can ensure no messages are missed, even in case of network issues or application crashes. . .Pp .%T IRCv3 Client Capability Negotiation specifies that capabilities MAY have values in .Ql CAP LS or .Ql CAP NEW responses. It does not, however, indicate if .Ql CAP REQ capabilities MUST NOT have values. The .Nm implementation parses .Ql CAP REQ values in the same way as .Ql CAP LS values. . .Pp The .Sy causal.agency/passive vendor-specific IRCv3 capability indicates that a client should not affect the automatic away status. . .Sh AUTHORS .An June McEnroe Aq Mt june@causal.agency . .Sh BUGS Send mail to .Aq Mt list+pounce@causal.agency or join .Li #ascii.town on .Li irc.tilde.chat . . .Pp A client will sometimes receive its own message, causing it to be displayed twice. This happens when a message is sent while responses are not yet consumed.