mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
242 lines
9 KiB
Text
242 lines
9 KiB
Text
|
|
This file should help you to add new address types and address options to
|
|
socat.
|
|
|
|
NOTE:
|
|
socat will in future releases be split into a library "libxio" containing all
|
|
the address stuff, useful also for many other purposes, and the socat main()
|
|
and data shuffler. If you intend to perform major changes to the xio part and
|
|
to publish them, please contact me before!
|
|
|
|
|
|
ADDING A NEW ADDRESS TYPE:
|
|
|
|
* Create new files xio-newaddr.c and xio-newaddr.h
|
|
|
|
* Create a new record of struct addrdesc in xio-newaddr.c, with declaration in xio-newaddr.h.
|
|
|
|
* Make a new entry to addressnames[] in xioopen.c with the addresses main name
|
|
and maybe with alias names. Keep this array ASCII sorted, without uppercase
|
|
chars.
|
|
|
|
* config.h.in: #undef WITH_NEWADDR
|
|
|
|
* configure.in: Copy the disable part of, e.g., WITH_SOCKS4 and adapt it to
|
|
NEWADDR
|
|
|
|
* In socat.c, add to socat_version
|
|
|
|
* Write a function xioopen_newaddr() in xio-newaddr.c, declaration in
|
|
xio-newaddr.h
|
|
Do not forget the following option processing calls:
|
|
All groups: _xio_openlate()
|
|
Group FD: applyopts_cloexec()
|
|
Group NAMED: applyopts_file() for phases PREOPEN, OPEN, and FD
|
|
|
|
* Describe a tested example in file EXAMPLES, and maybe in the socat manpage
|
|
source.
|
|
|
|
* Try to define a test for this address type in test.sh
|
|
|
|
* Update file CHANGES
|
|
|
|
|
|
ADDING A NEW ADDRESS OPTION:
|
|
|
|
xioopen.c:
|
|
|
|
* If this option depends on a #define that is probably not available on all
|
|
platforms, make all new code for this option dependent on the existence of this
|
|
C header define:
|
|
#ifdef PREFIX_NEWOPTION
|
|
...
|
|
#endif
|
|
|
|
* Add an OPT_NEWOPTION to enum e_optcode in xioopts.h, preferably keeping
|
|
alphabetic order
|
|
|
|
* Add a struct optdesc opt_newoption record in xio-newaddr.c and its
|
|
declaration in xio-newaddr.h. The complete structure definition must be in one
|
|
line without breaks for automatic docu extraction.
|
|
Build the record from the following components:
|
|
. A canonical default name (e.g. "newoption")
|
|
. A short, preferable name (e.g. "newopt") or NULL
|
|
. OPT_NEWOPTION (from enum e_optcode, see above)
|
|
. A group membership that restricts appliance of the new option to matching
|
|
address types (e.g., one of GROUP_ANY, GROUP_IP_TCP, GROUP_EXEC)
|
|
. A phase specification that positions this option within address processing.
|
|
Note that the function code can override this value.
|
|
. A representation type for option arguments (e.g., TYPE_INT, TYPE_STRING etc.;
|
|
use TYPE_BOOL if this option just triggers an action)
|
|
. A function or action definition for applying this option. If it does not use
|
|
one of the standard functions (open(), ioctl(), setsockopt()...), then use
|
|
OFUNC_SPEC (specific).
|
|
|
|
* For the canonical name and all its aliases and abbreviations, add entries to
|
|
the array optionnames in xioopts.c. KEEP STRICT ALPHABETIC (ASCII) ORDER!
|
|
The entries must be embedded in an IF_... macro of their group for conditional
|
|
compiling.
|
|
|
|
* For options using some predefined action (see OFUNC above), this might be
|
|
enough - test the option and document it in doc/socat.yo!
|
|
For OFUNC_SPEC, it might suffice to add another "case" to the OFUNC_SPEC branch
|
|
in applyopts() in xioopts.c. If you need more special handling, you should try
|
|
to understand the address specific functions and add your code there.
|
|
|
|
* If you use system or low level C library calls or library calls that might
|
|
hang or induce problems, please invoke them with capitalized name; if no such
|
|
name is defined, add an appropriate debug function to sycls.c, and a header
|
|
entry and a wrapper "define" to sycls.h
|
|
|
|
* Update file CHANGES
|
|
|
|
|
|
INFO ABOUT ADDRESS PHASES:
|
|
|
|
Each option entry has a field specifying a default phase for its application.
|
|
Of course, the code that analyses and applies an address may override this
|
|
default phase.
|
|
|
|
Depending on the type of address there are several major phase sequences:
|
|
|
|
|
|
OPEN addresses:
|
|
|
|
PH_INIT retrieving info from original state
|
|
PH_EARLY before any other processing
|
|
PH_PREOPEN before file creation/opening (not UNIX sockets)
|
|
PH_OPEN during file creation/opening (not UNIX sockets)
|
|
PH_PASTOPEN past file creation/opening (not UNIX sockets)
|
|
PH_FD soon after FD creation or identification
|
|
PH_LATE FD is ready, before start of data loop
|
|
PH_LATE2 FD is ready, dropping privileges
|
|
|
|
|
|
SOCKET addresses:
|
|
|
|
PH_INIT retrieving info from original state
|
|
PH_EARLY before any other processing
|
|
PH_PRESOCKET before socket call
|
|
PH_SOCKET for socket call
|
|
PH_PASTSOCKET after socket call
|
|
PH_FD soon after FD creation or identification
|
|
PH_PREBIND before socket bind()
|
|
PH_BIND during socket bind()
|
|
PH_PASTBIND past socket bind()
|
|
PH_PRECONNECT before connect()
|
|
PH_CONNECT during connect()
|
|
PH_PASTCONNECT after connect()
|
|
PH_CONNECTED phase common with listen
|
|
PH_LATE FD is ready, before start of data loop
|
|
PH_LATE2 FD is ready, dropping privileges
|
|
|
|
|
|
SOCKET with LISTEN and ACCEPT:
|
|
|
|
PH_INIT retrieving info from original state
|
|
PH_EARLY before any other processing
|
|
PH_PRESOCKET before socket call
|
|
PH_SOCKET for socket call
|
|
PH_PREBIND before socket bind()
|
|
PH_BIND during socket bind()
|
|
PH_PASTBIND past socket bind()
|
|
PH_PRELISTEN before listen()
|
|
PH_LISTEN during listen()
|
|
PH_PASTLISTEN after listen()
|
|
PH_PREACCEPT before accept()
|
|
PH_ACCEPT during accept()
|
|
PH_PASTACCEPT after accept()
|
|
# and the following on the new FD:
|
|
PH_FD soon after FD creation or identification
|
|
PH_PASTSOCKET after socket call
|
|
PH_CONNECTED phase common with connect
|
|
PH_PREFORK before forking
|
|
PH_FORK during fork()
|
|
PH_PASTFORK after fork()
|
|
PH_LATE FD is ready, before start of data loop
|
|
PH_LATE2 FD is ready, dropping privileges
|
|
|
|
|
|
Passive UNIX socket addresses; this is a mix of socket phases and file system phases:
|
|
PH_INIT retrieving info from original state
|
|
PH_EARLY before any other processing
|
|
PH_PRESOCKET before socket call
|
|
PH_SOCKET for socket call
|
|
PH_PASTSOCKET after socket call
|
|
PH_FD soon after FD creation or identification
|
|
PH_PREOPEN before file creation/opening
|
|
PH_PREBIND before socket bind()
|
|
PH_BIND during socket bind()
|
|
PH_PASTOPEN past file creation/opening
|
|
PH_PASTBIND past socket bind(), not used up to 1.7.3.4
|
|
PH_PRECONNECT before connect()
|
|
PH_CONNECT during connect()
|
|
PH_PASTCONNECT after connect()
|
|
PH_CONNECTED phase common with listen
|
|
PH_LATE FD is ready, before start of data loop
|
|
PH_LATE2 FD is ready, dropping privileges
|
|
|
|
|
|
FD addresses:
|
|
|
|
PH_INIT retrieving info from original state
|
|
PH_EARLY before any other processing
|
|
PH_FD soon after FD identification
|
|
PH_LATE FD is ready, before start of data loop
|
|
PH_LATE2 FD is ready, dropping privileges
|
|
|
|
|
|
EXEC addresses:
|
|
|
|
PH_INIT retrieving info from original state
|
|
PH_EARLY before any other processing
|
|
PH_PREBIGEN before socketpair() pipe() openpty()
|
|
PH_BIGEN during socketpair() pipe() openpty()
|
|
PH_PASTBIGEN past socketpair() pipe() openpty()
|
|
PH_PASTSOCKET for socketpair()
|
|
PH_FD soon after FD creation or identification
|
|
PH_PREFORK before forking
|
|
PH_FORK during fork()
|
|
PH_PASTFORK after fork()
|
|
PH_LATE FD is ready, before start of data loop
|
|
PH_LATE2 FD is ready, dropping privileges
|
|
PH_PREEXEC before exec() or system()
|
|
PH_EXEC during exec() or system()
|
|
|
|
|
|
There are lots of semantic relations between group, phase, and func fields of
|
|
an option.
|
|
|
|
|
|
There exists something like an overall phase sequence:
|
|
PH_INIT # su-d.1
|
|
PH_EARLY # chroot-early
|
|
PH_PREOPEN, PH_OPEN, PH_PASTOPEN # (chroot before/after?)
|
|
PH_PRESOCKET, PH_SOCKET, PH_PASTSOCKET # (su after (root for raw)?)
|
|
PH_PREBIGEN, PH_BIGEN, PH_PASTBIGEN # (chroot before/after (/dev..)?)
|
|
PH_FD
|
|
PH_PREBIND, PH_BIND, PH_PASTBIND # (su after(before?))
|
|
PH_PRELISTEN, PH_LISTEN, PH_PASTLISTEN
|
|
PH_PRECONNECT, PH_CONNECT, PH_PASTCONNECT # (chroot before/after (AF_UNIX)?)
|
|
PH_PREACCEPT, PH_ACCEPT, PH_PASTACCEPT
|
|
PH_CONNECTED
|
|
PH_PREFORK, PH_FORK, PH_PASTFORK # (all before/after?)
|
|
PH_LATE # chroot
|
|
PH_LATE2 # su, su-d.2
|
|
PH_PREEXEC, PH_EXEC # (all before)
|
|
|
|
===============================================================================
|
|
// Up to 1.7.2.4 socat used non async signal safe system and library calls in signal handlers, mostly for logging purposes. This problem was fixed in release 1.7.3.0 with the following concepts:
|
|
|
|
Signal handlers set on entry and unset on return the diag_in_handler global variable. The logging system, when this variable is set, queues the text message together with errno and exit info in a UNIX datagram socket. When invoked with unset diag_in_handler it first checks if there are messages in that queue and prints them first.
|
|
|
|
A async signal safe but minimal version of vsnprintf, named vsnprintf_r, was written so no value arguments need to be queued.
|
|
|
|
Because strerror is not async signal safe a new function snprinterr was written that replaces the (glibc compatible) %m format with strerror output. The original errno is passed in the message queue, snprinterr is called when dequeuing messages outside of signal handler.
|
|
|
|
// List of signal handlers in socat
|
|
socat.c:socat_signal (generic, just logs and maybe exits)
|
|
xioshutdown.c:signal_kill_pid (SIGALRM, kill child process)
|
|
xiosigchld.c:childdied (SIGCHLD: get info, log; possibly close channel)
|
|
xiosignal.c:socatsignalpass: cascades signal to channel child processes; w/ options sighup,sigint,sigquit
|
|
xio-socket.c:xiosigaction_hasread: SIGUSR1,SIGCHLD, tells parent that datagram has been consumed
|