1 /* source: xio-socket.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
4 
5 /* this file contains the source for socket related functions, and the
6    implementation of generic socket addresses */
7 
8 #include "xiosysincludes.h"
9 
10 #if _WITH_SOCKET
11 
12 #include "xioopen.h"
13 #include "xio-ascii.h"
14 #include "xio-socket.h"
15 #include "xio-named.h"
16 #include "xio-unix.h"
17 #if WITH_IP4
18 #include "xio-ip4.h"
19 #endif /* WITH_IP4 */
20 #if WITH_IP6
21 #include "xio-ip6.h"
22 #endif /* WITH_IP6 */
23 #include "xio-ip.h"
24 #include "xio-listen.h"
25 #include "xio-ipapp.h"	/*! not clean */
26 #include "xio-tcpwrap.h"
27 
28 
29 static
30 int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
31 			   int xioflags, xiofile_t *xfd, unsigned groups,
32 			   int dummy1, int dummy2, int dummy3);
33 static
34 int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
35 			  int xioflags, xiofile_t *xfd, unsigned groups,
36 			  int dummy1, int dummy2, int dummy3);
37 static
38 int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
39 			  int xioflags, xiofile_t *xfd, unsigned groups,
40 			  int dummy1, int dummy2, int dummy3);
41 static
42 int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
43 			    int xioflags, xiofile_t *xfd, unsigned groups,
44 			    int dummy1, int dummy2, int dummy3);
45 static
46 int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
47 			    int xioflags, xiofile_t *xfd, unsigned groups,
48 			    int dummy1, int socktype, int dummy3);
49 static
50 int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
51 			int xioflags, xiofile_t *xfd, unsigned groups,
52 			int dumy1, int dummy2, int dummy3);
53 
54 static
55 int _xioopen_socket_sendto(const char *pfname, const char *type,
56 			   const char *proto, const char *address,
57 			   struct opt *opts, int xioflags, xiofile_t *xxfd,
58 			   unsigned groups);
59 
60 static int
61 xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
62 			char *typbuff, int typlen,
63 			char *nambuff, int namlen,
64 			char *envbuff, int envlen,
65 			char *valbuff, int vallen);
66 
67 
68 #if WITH_GENERICSOCKET
69 /* generic socket addresses */
70 const struct addrdesc xioaddr_socket_connect = { "socket-connect",     1, xioopen_socket_connect,  GROUP_FD|GROUP_SOCKET|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<domain>:<protocol>:<remote-address>") };
71 #if WITH_LISTEN
72 const struct addrdesc xioaddr_socket_listen  = { "socket-listen",      1, xioopen_socket_listen,   GROUP_FD|GROUP_SOCKET|GROUP_LISTEN|GROUP_RANGE|GROUP_CHILD|GROUP_RETRY, 0, 0, 0 HELP(":<domain>:<protocol>:<local-address>") };
73 #endif /* WITH_LISTEN */
74 const struct addrdesc xioaddr_socket_sendto  = { "socket-sendto",      3, xioopen_socket_sendto,   GROUP_FD|GROUP_SOCKET,                         0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
75 const struct addrdesc xioaddr_socket_datagram= { "socket-datagram",    3, xioopen_socket_datagram, GROUP_FD|GROUP_SOCKET|GROUP_RANGE,             0, 0, 0 HELP(":<domain>:<type>:<protocol>:<remote-address>") };
76 const struct addrdesc xioaddr_socket_recvfrom= { "socket-recvfrom",    3, xioopen_socket_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_RANGE|GROUP_CHILD, 0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
77 const struct addrdesc xioaddr_socket_recv    = { "socket-recv",        1, xioopen_socket_recv,     GROUP_FD|GROUP_SOCKET|GROUP_RANGE,             0, 0, 0 HELP(":<domain>:<type>:<protocol>:<local-address>") };
78 #endif /* WITH_GENERICSOCKET */
79 
80 
81 /* the following options apply not only to generic socket addresses but to all
82    addresses that have anything to do with sockets */
83 const struct optdesc opt_so_debug    = { "so-debug",    "debug", OPT_SO_DEBUG,    GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_DEBUG };
84 #ifdef SO_ACCEPTCONN /* AIX433 */
85 const struct optdesc opt_so_acceptconn={ "so-acceptconn","acceptconn",OPT_SO_ACCEPTCONN,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_ACCEPTCONN};
86 #endif /* SO_ACCEPTCONN */
87 const struct optdesc opt_so_broadcast= { "so-broadcast", "broadcast", OPT_SO_BROADCAST,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_BROADCAST};
88 const struct optdesc opt_so_reuseaddr= { "so-reuseaddr", "reuseaddr", OPT_SO_REUSEADDR,GROUP_SOCKET, PH_PREBIND, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEADDR};
89 const struct optdesc opt_so_keepalive= { "so-keepalive", "keepalive", OPT_SO_KEEPALIVE,GROUP_SOCKET, PH_FD, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_KEEPALIVE};
90 #if HAVE_STRUCT_LINGER
91 const struct optdesc opt_so_linger   = { "so-linger",    "linger",    OPT_SO_LINGER,   GROUP_SOCKET, PH_PASTSOCKET, TYPE_LINGER,OFUNC_SOCKOPT,SOL_SOCKET, SO_LINGER };
92 #else /* !HAVE_STRUCT_LINGER */
93 const struct optdesc opt_so_linger   = { "so-linger",    "linger",    OPT_SO_LINGER,   GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_LINGER };
94 #endif /* !HAVE_STRUCT_LINGER */
95 const struct optdesc opt_so_oobinline= { "so-oobinline", "oobinline", OPT_SO_OOBINLINE,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_OOBINLINE};
96 const struct optdesc opt_so_sndbuf   = { "so-sndbuf",    "sndbuf",    OPT_SO_SNDBUF,   GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_SNDBUF};
97 const struct optdesc opt_so_sndbuf_late={ "so-sndbuf-late","sndbuf-late",OPT_SO_SNDBUF_LATE,GROUP_SOCKET,PH_LATE,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SNDBUF };
98 const struct optdesc opt_so_rcvbuf   = { "so-rcvbuf",    "rcvbuf",    OPT_SO_RCVBUF,   GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVBUF};
99 const struct optdesc opt_so_rcvbuf_late={"so-rcvbuf-late","rcvbuf-late",OPT_SO_RCVBUF_LATE,GROUP_SOCKET,PH_LATE,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_RCVBUF };
100 const struct optdesc opt_so_error    = { "so-error",     "error",     OPT_SO_ERROR,    GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_ERROR};
101 const struct optdesc opt_so_type     = { "so-type",      "type",      OPT_SO_TYPE,     GROUP_SOCKET, PH_SOCKET,     TYPE_INT,  OFUNC_SPEC,    SOL_SOCKET, SO_TYPE };
102 const struct optdesc opt_so_dontroute= { "so-dontroute", "dontroute", OPT_SO_DONTROUTE,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_DONTROUTE };
103 #ifdef SO_RCVLOWAT
104 const struct optdesc opt_so_rcvlowat = { "so-rcvlowat",  "rcvlowat", OPT_SO_RCVLOWAT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_RCVLOWAT };
105 #endif
106 #ifdef SO_SNDLOWAT
107 const struct optdesc opt_so_sndlowat = { "so-sndlowat",  "sndlowat", OPT_SO_SNDLOWAT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_SNDLOWAT };
108 #endif
109 /* end of setsockopt options of UNIX98 standard */
110 
111 #ifdef SO_AUDIT	/* AIX 4.3.3 */
112 const struct optdesc opt_so_audit    = { "so-audit",     "audit",    OPT_SO_AUDIT,    GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_AUDIT };
113 #endif /* SO_AUDIT */
114 #ifdef SO_ATTACH_FILTER
115 const struct optdesc opt_so_attach_filter={"so-attach-filter","attachfilter",OPT_SO_ATTACH_FILTER,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_ATTACH_FILTER};
116 #endif
117 #ifdef SO_DETACH_FILTER
118 const struct optdesc opt_so_detach_filter={"so-detach-filter","detachfilter",OPT_SO_DETACH_FILTER,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DETACH_FILTER};
119 #endif
120 #ifdef SO_BINDTODEVICE	/* Linux: man 7 socket */
121 const struct optdesc opt_so_bindtodevice={"so-bindtodevice","if",OPT_SO_BINDTODEVICE,GROUP_SOCKET,PH_PASTSOCKET,TYPE_NAME,OFUNC_SOCKOPT,SOL_SOCKET,SO_BINDTODEVICE};
122 #endif
123 #ifdef SO_BSDCOMPAT
124 const struct optdesc opt_so_bsdcompat= { "so-bsdcompat","bsdcompat",OPT_SO_BSDCOMPAT,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_BSDCOMPAT };
125 #endif
126 #ifdef SO_CKSUMRECV
127 const struct optdesc opt_so_cksumrecv= { "so-cksumrecv","cksumrecv",OPT_SO_CKSUMRECV,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_CKSUMRECV };
128 #endif /* SO_CKSUMRECV */
129 #ifdef SO_TIMESTAMP
130 const struct optdesc opt_so_timestamp= { "so-timestamp","timestamp",OPT_SO_TIMESTAMP,GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_TIMESTAMP };
131 #endif
132 #ifdef SO_KERNACCEPT	/* AIX 4.3.3 */
133 const struct optdesc opt_so_kernaccept={ "so-kernaccept","kernaccept",OPT_SO_KERNACCEPT,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_KERNACCEPT};
134 #endif /* SO_KERNACCEPT */
135 #ifdef SO_NO_CHECK
136 const struct optdesc opt_so_no_check = { "so-no-check", "nocheck",OPT_SO_NO_CHECK, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_NO_CHECK };
137 #endif
138 #ifdef SO_NOREUSEADDR	/* AIX 4.3.3 */
139 const struct optdesc opt_so_noreuseaddr={"so-noreuseaddr","noreuseaddr",OPT_SO_NOREUSEADDR,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET, SO_NOREUSEADDR};
140 #endif /* SO_NOREUSEADDR */
141 #ifdef SO_PASSCRED
142 const struct optdesc opt_so_passcred = { "so-passcred", "passcred", OPT_SO_PASSCRED, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_PASSCRED};
143 #endif
144 #ifdef SO_PEERCRED
145 const struct optdesc opt_so_peercred = { "so-peercred", "peercred", OPT_SO_PEERCRED, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT3,OFUNC_SOCKOPT, SOL_SOCKET, SO_PEERCRED};
146 #endif
147 #ifdef SO_PRIORITY
148 const struct optdesc opt_so_priority = { "so-priority", "priority", OPT_SO_PRIORITY, GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_PRIORITY};
149 #endif
150 #ifdef SO_REUSEPORT	/* AIX 4.3.3, BSD, HP-UX, Linux >=3.9 */
151 const struct optdesc opt_so_reuseport= { "so-reuseport","reuseport",OPT_SO_REUSEPORT,GROUP_SOCKET, PH_PREBIND, TYPE_INT, OFUNC_SOCKOPT, SOL_SOCKET, SO_REUSEPORT };
152 #endif /* defined(SO_REUSEPORT) */
153 #ifdef SO_SECURITY_AUTHENTICATION
154 const struct optdesc opt_so_security_authentication={"so-security-authentication","securityauthentication",OPT_SO_SECURITY_AUTHENTICATION,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SECURITY_AUTHENTICATION};
155 #endif
156 #ifdef SO_SECURITY_ENCRYPTION_NETWORK
157 const struct optdesc opt_so_security_encryption_network={"so-security-encryption-network","securityencryptionnetwork",OPT_SO_SECURITY_ENCRYPTION_NETWORK,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SECURITY_ENCRYPTION_NETWORK};
158 #endif
159 #ifdef SO_SECURITY_ENCRYPTION_TRANSPORT
160 const struct optdesc opt_so_security_encryption_transport={"so-security-encryption-transport","securityencryptiontransport",OPT_SO_SECURITY_ENCRYPTION_TRANSPORT,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_SECURITY_ENCRYPTION_TRANSPORT};
161 #endif
162 #ifdef SO_USE_IFBUFS
163 const struct optdesc opt_so_use_ifbufs={ "so-use-ifbufs","useifbufs",OPT_SO_USE_IFBUFS,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,  OFUNC_SOCKOPT, SOL_SOCKET, SO_USE_IFBUFS};
164 #endif /* SO_USE_IFBUFS */
165 #ifdef SO_USELOOPBACK /* AIX433, Solaris, HP-UX */
166 const struct optdesc opt_so_useloopback={"so-useloopback","useloopback",OPT_SO_USELOOPBACK,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT, SOL_SOCKET, SO_USELOOPBACK};
167 #endif /* SO_USELOOPBACK */
168 #ifdef SO_DGRAM_ERRIND	/* Solaris */
169 const struct optdesc opt_so_dgram_errind={"so-dgram-errind","dgramerrind",OPT_SO_DGRAM_ERRIND,GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DGRAM_ERRIND};
170 #endif /* SO_DGRAM_ERRIND */
171 #ifdef SO_DONTLINGER	/* Solaris */
172 const struct optdesc opt_so_dontlinger = {"so-dontlinger", "dontlinger",  OPT_SO_DONTLINGER,  GROUP_SOCKET,PH_PASTSOCKET,TYPE_INT,OFUNC_SOCKOPT,SOL_SOCKET,SO_DONTLINGER };
173 #endif
174 /* the SO_PROTOTYPE is OS defined on Solaris, HP-UX; we lend this for a more
175    general purpose */
176 const struct optdesc opt_so_prototype  = {"so-protocol",  "protocol",   OPT_SO_PROTOTYPE,   GROUP_SOCKET,PH_SOCKET,    TYPE_INT,OFUNC_SPEC,   SOL_SOCKET,SO_PROTOCOL };
177 #ifdef FIOSETOWN
178 const struct optdesc opt_fiosetown   = { "fiosetown", NULL, OPT_FIOSETOWN,   GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_IOCTL,  FIOSETOWN };
179 #endif
180 #ifdef SIOCSPGRP
181 const struct optdesc opt_siocspgrp   = { "siocspgrp", NULL, OPT_SIOCSPGRP,   GROUP_SOCKET, PH_PASTSOCKET, TYPE_INT,  OFUNC_IOCTL,  SIOCSPGRP };
182 #endif
183 const struct optdesc opt_bind        = { "bind",      NULL, OPT_BIND,        GROUP_SOCKET, PH_BIND, TYPE_STRING,OFUNC_SPEC };
184 const struct optdesc opt_connect_timeout = { "connect-timeout", NULL, OPT_CONNECT_TIMEOUT, GROUP_SOCKET, PH_PASTSOCKET, TYPE_TIMEVAL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.connect_timeout) };
185 const struct optdesc opt_protocol_family = { "protocol-family", "pf", OPT_PROTOCOL_FAMILY, GROUP_SOCKET, PH_PRESOCKET,  TYPE_STRING,  OFUNC_SPEC };
186 const struct optdesc opt_protocol        = { "protocol",        NULL, OPT_PROTOCOL,        GROUP_SOCKET, PH_PRESOCKET,  TYPE_STRING,  OFUNC_SPEC };
187 
188 /* generic setsockopt() options */
189 const struct optdesc opt_setsockopt        = { "setsockopt",        "sockopt",        OPT_SETSOCKOPT_BIN,        GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_BIN,     OFUNC_SOCKOPT_GENERIC, 0, 0 };
190 const struct optdesc opt_setsockopt_int    = { "setsockopt-int",    "sockopt-int",    OPT_SETSOCKOPT_INT,        GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_INT,     OFUNC_SOCKOPT_GENERIC, 0, 0 };
191 const struct optdesc opt_setsockopt_bin    = { "setsockopt-bin",    "sockopt-bin",    OPT_SETSOCKOPT_BIN,        GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_BIN,     OFUNC_SOCKOPT_GENERIC, 0, 0 };
192 const struct optdesc opt_setsockopt_string = { "setsockopt-string", "sockopt-string", OPT_SETSOCKOPT_STRING,     GROUP_SOCKET,PH_CONNECTED, TYPE_INT_INT_STRING,  OFUNC_SOCKOPT_GENERIC, 0, 0 };
193 const struct optdesc opt_setsockopt_listen = { "setsockopt-listen", "sockopt-listen", OPT_SETSOCKOPT_LISTEN,     GROUP_SOCKET,PH_PREBIND,   TYPE_INT_INT_BIN,     OFUNC_SOCKOPT_GENERIC, 0, 0 };
194 
195 const struct optdesc opt_null_eof = { "null-eof", NULL, OPT_NULL_EOF, GROUP_SOCKET, PH_INIT, TYPE_BOOL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.null_eof) };
196 
197 
198 #if WITH_GENERICSOCKET
199 
200 static
xioopen_socket_connect(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int dummy1,int dummy2,int dummy3)201 int xioopen_socket_connect(int argc, const char *argv[], struct opt *opts,
202 			   int xioflags, xiofile_t *xxfd, unsigned groups,
203 			   int dummy1, int dummy2, int dummy3) {
204    struct single *xfd = &xxfd->stream;
205    const char *pfname = argv[1];
206    const char *protname = argv[2];
207    const char *address = argv[3];
208    char *garbage;
209    int pf;
210    int proto;
211    int socktype = SOCK_STREAM;
212    int needbind = 0;
213    union sockaddr_union them;  socklen_t themlen; size_t themsize;
214    union sockaddr_union us;    socklen_t uslen = sizeof(us);
215    int result;
216 
217    if (argc != 4) {
218       Error2("%s: wrong number of parameters (%d instead of 3)",
219 	     argv[0], argc-1);
220       return STAT_NORETRY;
221    }
222 
223    pf = strtoul(pfname, &garbage, 0);
224    if (*garbage != '\0') {
225       Warn1("garbage in parameter: \"%s\"", garbage);
226    }
227 
228    proto = strtoul(protname, &garbage, 0);
229    if (*garbage != '\0') {
230       Warn1("garbage in parameter: \"%s\"", garbage);
231    }
232 
233    retropt_socket_pf(opts, &pf);
234    retropt_int(opts, OPT_SO_TYPE, &socktype);
235    /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
236    xfd->howtoend = END_SHUTDOWN;
237 
238    if (applyopts_single(xfd, opts, PH_INIT) < 0)  return -1;
239    applyopts(-1, opts, PH_INIT);
240    applyopts(-1, opts, PH_EARLY);
241 
242    themsize = 0;
243    if ((result =
244 	dalan(address, (uint8_t *)&them.soa.sa_data, &themsize, sizeof(them), 'i'))
245        < 0) {
246       Error1("data too long: \"%s\"", address);
247    } else if (result > 0) {
248       Error1("syntax error in \"%s\"", address);
249    }
250    them.soa.sa_family = pf;
251    themlen = themsize +
252 #if HAVE_STRUCT_SOCKADDR_SALEN
253       sizeof(them.soa.sa_len) +
254 #endif
255       sizeof(them.soa.sa_family);
256 
257    xfd->dtype = XIOREAD_STREAM|XIOWRITE_STREAM;
258 
259    socket_init(0, &us);
260    if (retropt_bind(opts, 0 /*pf*/, socktype, proto, (struct sockaddr *)&us, &uslen, 3,
261 		    0, 0)
262        != STAT_NOACTION) {
263       needbind = true;
264       us.soa.sa_family = pf;
265    }
266 
267    if ((result =
268 	xioopen_connect(xfd,
269 			needbind?&us:NULL, uslen,
270 			(struct sockaddr *)&them, themlen,
271 			opts, pf, socktype, proto, false)) != 0) {
272       return result;
273    }
274    if ((result = _xio_openlate(xfd, opts)) < 0) {
275       return result;
276    }
277    return STAT_OK;
278 }
279 
280 #if WITH_LISTEN
281 static
xioopen_socket_listen(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int dummy1,int dummy2,int dummy3)282 int xioopen_socket_listen(int argc, const char *argv[], struct opt *opts,
283 			  int xioflags, xiofile_t *xxfd, unsigned groups,
284 			  int dummy1, int dummy2, int dummy3) {
285    struct single *xfd = &xxfd->stream;
286    const char *pfname = argv[1];
287    const char *protname = argv[2];
288    const char *usname = argv[3];
289    char *garbage;
290    int pf;
291    int proto;
292    int socktype = SOCK_STREAM;
293    union sockaddr_union us;  socklen_t uslen; size_t ussize;
294    struct opt *opts0;
295    int result;
296 
297    if (argc != 4) {
298       Error2("%s: wrong number of parameters (%d instead of 3)",
299 	     argv[0], argc-1);
300       return STAT_NORETRY;
301    }
302 
303    pf = strtoul(pfname, &garbage, 0);
304    if (*garbage != '\0') {
305       Warn1("garbage in parameter: \"%s\"", garbage);
306    }
307 
308    proto = strtoul(protname, &garbage, 0);
309    if (*garbage != '\0') {
310       Warn1("garbage in parameter: \"%s\"", garbage);
311    }
312 
313    retropt_socket_pf(opts, &pf);
314    retropt_int(opts, OPT_SO_TYPE, &socktype);
315    /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
316    xfd->howtoend = END_SHUTDOWN;
317 
318    socket_init(0, &us);
319    ussize = 0;
320    if ((result =
321 	dalan(usname, (uint8_t *)&us.soa.sa_data, &ussize, sizeof(us), 'i'))
322        < 0) {
323       Error1("data too long: \"%s\"", usname);
324    } else if (result > 0) {
325       Error1("syntax error in \"%s\"", usname);
326    }
327    uslen = ussize + sizeof(us.soa.sa_family)
328 #if HAVE_STRUCT_SOCKADDR_SALEN
329       + sizeof(us.soa.sa_len)
330 #endif
331       ;
332    us.soa.sa_family = pf;
333 
334    if (applyopts_single(xfd, opts, PH_INIT) < 0)  return -1;
335    applyopts(-1, opts, PH_INIT);
336    applyopts(-1, opts, PH_EARLY);
337 
338    opts0 = copyopts(opts, GROUP_ALL);
339 
340    if ((result =
341 	xioopen_listen(xfd, xioflags,
342 		       &us.soa, uslen,
343 		       opts, opts0, 0/*instead of pf*/, socktype, proto))
344        != STAT_OK)
345       return result;
346    return STAT_OK;
347 }
348 #endif /* WITH_LISTEN */
349 
350 /* we expect the form: ...:domain:type:protocol:remote-address */
351 static
xioopen_socket_sendto(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int dummy1,int dummy2,int dummy3)352 int xioopen_socket_sendto(int argc, const char *argv[], struct opt *opts,
353 			  int xioflags, xiofile_t *xxfd, unsigned groups,
354 			  int dummy1, int dummy2, int dummy3) {
355    int result;
356 
357    if (argc != 5) {
358       Error2("%s: wrong number of parameters (%d instead of 4)",
359 	     argv[0], argc-1);
360       return STAT_NORETRY;
361    }
362    if ((result =
363 	   _xioopen_socket_sendto(argv[1], argv[2], argv[3], argv[4],
364 				  opts, xioflags, xxfd, groups))
365        != STAT_OK) {
366       return result;
367    }
368    _xio_openlate(&xxfd->stream, opts);
369    return STAT_OK;
370 }
371 
372 static
_xioopen_socket_sendto(const char * pfname,const char * type,const char * protname,const char * address,struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups)373 int _xioopen_socket_sendto(const char *pfname, const char *type,
374 			   const char *protname, const char *address,
375 			   struct opt *opts, int xioflags, xiofile_t *xxfd,
376 			   unsigned groups) {
377    xiosingle_t *xfd = &xxfd->stream;
378    char *garbage;
379    union sockaddr_union us = {{0}};
380    socklen_t uslen = 0;   size_t ussize;
381    size_t themsize;
382    int pf;
383    int socktype = SOCK_RAW;
384    int proto;
385    bool needbind = false;
386    char *bindstring = NULL;
387    int result;
388 
389    pf = strtoul(pfname, &garbage, 0);
390    if (*garbage != '\0') {
391       Warn1("garbage in parameter: \"%s\"", garbage);
392    }
393 
394    socktype = strtoul(type, &garbage, 0);
395    if (*garbage != '\0') {
396       Warn1("garbage in parameter: \"%s\"", garbage);
397    }
398 
399    proto = strtoul(protname, &garbage, 0);
400    if (*garbage != '\0') {
401       Warn1("garbage in parameter: \"%s\"", garbage);
402    }
403 
404    retropt_socket_pf(opts, &pf);
405    retropt_int(opts, OPT_SO_TYPE, &socktype);
406    /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
407    xfd->howtoend = END_SHUTDOWN;
408 
409    xfd->peersa.soa.sa_family = pf;
410    themsize = 0;
411    if ((result =
412 	dalan(address, (uint8_t *)&xfd->peersa.soa.sa_data, &themsize,
413 	      sizeof(xfd->peersa), 'i'))
414        < 0) {
415       Error1("data too long: \"%s\"", address);
416    } else if (result > 0) {
417       Error1("syntax error in \"%s\"", address);
418    }
419    xfd->salen = themsize + sizeof(sa_family_t)
420 #if HAVE_STRUCT_SOCKADDR_SALEN
421       + sizeof(xfd->peersa.soa.sa_len)
422 #endif
423       ;
424 #if HAVE_STRUCT_SOCKADDR_SALEN
425    xfd->peersa.soa.sa_len =
426       sizeof(xfd->peersa.soa.sa_len) + sizeof(xfd->peersa.soa.sa_family) +
427       themsize;
428 #endif
429 
430    /* ...res_opts[] */
431    if (applyopts_single(xfd, opts, PH_INIT) < 0)  return -1;
432    applyopts(-1, opts, PH_INIT);
433 
434    if (pf == PF_UNSPEC) {
435       pf = xfd->peersa.soa.sa_family;
436    }
437 
438    xfd->dtype = XIODATA_RECVFROM;
439 
440    if (retropt_string(opts, OPT_BIND, &bindstring) == 0) {
441       ussize = 0;
442       if ((result =
443 	   dalan(bindstring, (uint8_t *)&us.soa.sa_data, &ussize, sizeof(us), 'i'))
444 	  < 0) {
445 	 Error1("data too long: \"%s\"", bindstring);
446       } else if (result > 0) {
447 	 Error1("syntax error in \"%s\"", bindstring);
448       }
449       us.soa.sa_family = pf;
450       uslen = ussize + sizeof(sa_family_t)
451 #if HAVE_STRUCT_SOCKADDR_SALEN
452 	 + sizeof(us.soa.sa_len)
453 #endif
454 	 ;
455       needbind = true;
456    }
457 
458    return
459       _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
460 			  opts, xioflags, xfd, groups, pf, socktype, proto);
461 }
462 
463 
464 /* we expect the form: ...:domain:socktype:protocol:local-address */
465 static
xioopen_socket_recvfrom(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int dummy,int summy2,int dummy3)466 int xioopen_socket_recvfrom(int argc, const char *argv[], struct opt *opts,
467 		     int xioflags, xiofile_t *xxfd, unsigned groups,
468 		     int dummy, int summy2, int dummy3) {
469    struct single *xfd = &xxfd->stream;
470    const char *pfname = argv[1];
471    const char *typename = argv[2];
472    const char *protname = argv[3];
473    const char *address = argv[4];
474    char *garbage;
475    union sockaddr_union *us = &xfd->para.socket.la;
476    socklen_t uslen; size_t ussize;
477    int pf, socktype, proto;
478    char *rangename;
479    int result;
480 
481    if (argc != 5) {
482       Error2("%s: wrong number of parameters (%d instead of 4)",
483 	     argv[0], argc-1);
484       return STAT_NORETRY;
485    }
486 
487    pf = strtoul(pfname, &garbage, 0);
488    if (*garbage != '\0') {
489       Warn1("garbage in parameter: \"%s\"", garbage);
490    }
491 
492    socktype = strtoul(typename, &garbage, 0);
493    if (*garbage != '\0') {
494       Warn1("garbage in parameter: \"%s\"", garbage);
495    }
496 
497    proto = strtoul(protname, &garbage, 0);
498    if (*garbage != '\0') {
499       Warn1("garbage in parameter: \"%s\"", garbage);
500    }
501 
502    retropt_socket_pf(opts, &pf);
503    retropt_int(opts, OPT_SO_TYPE, &socktype);
504    /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
505    xfd->howtoend = END_NONE;
506 
507    ussize = 0;
508    if ((result =
509 	dalan(address, (uint8_t *)&us->soa.sa_data, &ussize, sizeof(*us), 'i'))
510        < 0) {
511       Error1("data too long: \"%s\"", address);
512    } else if (result > 0) {
513       Error1("syntax error in \"%s\"", address);
514    }
515    us->soa.sa_family = pf;
516    uslen = ussize + sizeof(us->soa.sa_family)
517 #if HAVE_STRUCT_SOCKADDR_SALEN
518       + sizeof(us->soa.sa_len);
519 #endif
520       ;
521    xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
522 
523    if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
524       if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
525 	 return STAT_NORETRY;
526       }
527       xfd->para.socket.dorange = true;
528       free(rangename);
529    }
530 
531    if ((result =
532 	_xioopen_dgram_recvfrom(xfd, xioflags, &us->soa, uslen,
533 				opts, pf, socktype, proto, E_ERROR))
534        != STAT_OK) {
535       return result;
536    }
537    _xio_openlate(xfd, opts);
538    return STAT_OK;
539 }
540 
541 /* we expect the form: ...:domain:type:protocol:local-address */
542 static
xioopen_socket_recv(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int dummy1,int dummy2,int dummy3)543 int xioopen_socket_recv(int argc, const char *argv[], struct opt *opts,
544 		       int xioflags, xiofile_t *xxfd, unsigned groups,
545 		       int dummy1, int dummy2, int dummy3) {
546    struct single *xfd = &xxfd->stream;
547    const char *pfname = argv[1];
548    const char *typename = argv[2];
549    const char *protname = argv[3];
550    const char *address = argv[4];
551    char *garbage;
552    union sockaddr_union us;
553    socklen_t uslen; size_t ussize;
554    int pf, socktype, proto;
555    char *rangename;
556    int result;
557 
558    if (argc != 5) {
559       Error2("%s: wrong number of parameters (%d instead of 4)",
560 	     argv[0], argc-1);
561       return STAT_NORETRY;
562    }
563 
564    pf = strtoul(pfname, &garbage, 0);
565    if (*garbage != '\0') {
566       Warn1("garbage in parameter: \"%s\"", garbage);
567    }
568 
569    socktype = strtoul(typename, &garbage, 0);
570    if (*garbage != '\0') {
571       Warn1("garbage in parameter: \"%s\"", garbage);
572    }
573 
574    proto = strtoul(protname, &garbage, 0);
575    if (*garbage != '\0') {
576       Warn1("garbage in parameter: \"%s\"", garbage);
577    }
578 
579    retropt_socket_pf(opts, &pf);
580    retropt_int(opts, OPT_SO_TYPE, &socktype);
581    /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
582    xfd->howtoend = END_NONE;
583 
584    ussize = 0;
585    if ((result =
586 	dalan(address, (uint8_t *)&us.soa.sa_data, &ussize, sizeof(us), 'i'))
587        < 0) {
588       Error1("data too long: \"%s\"", address);
589    } else if (result > 0) {
590       Error1("syntax error in \"%s\"", address);
591    }
592    us.soa.sa_family = pf;
593    uslen = ussize + sizeof(sa_family_t)
594 #if HAVE_STRUCT_SOCKADDR_SALEN
595       +sizeof(us.soa.sa_len)
596 #endif
597       ;
598    xfd->dtype = XIOREAD_RECV;
599    xfd->para.socket.la.soa.sa_family = pf;
600 
601    if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
602       if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
603 	 return STAT_NORETRY;
604       }
605       xfd->para.socket.dorange = true;
606       free(rangename);
607    }
608 
609    if ((result =
610 	_xioopen_dgram_recv(xfd, xioflags, &us.soa,
611 			    uslen, opts, pf, socktype, proto, E_ERROR))
612        != STAT_OK) {
613       return result;
614    }
615    _xio_openlate(xfd, opts);
616    return STAT_OK;
617 }
618 
619 
620 /* we expect the form: ...:domain:type:protocol:remote-address */
621 static
xioopen_socket_datagram(int argc,const char * argv[],struct opt * opts,int xioflags,xiofile_t * xxfd,unsigned groups,int dummy1,int dummy2,int dummy3)622 int xioopen_socket_datagram(int argc, const char *argv[], struct opt *opts,
623 			    int xioflags, xiofile_t *xxfd, unsigned groups,
624 			    int dummy1, int dummy2, int dummy3) {
625    xiosingle_t *xfd = &xxfd->stream;
626    const char *pfname = argv[1];
627    const char *typename = argv[2];
628    const char *protname = argv[3];
629    const char *address = argv[4];
630    char *garbage;
631    char *rangename;
632    size_t themsize;
633    int pf;
634    int result;
635 
636    if (argc != 5) {
637       Error2("%s: wrong number of parameters (%d instead of 4)",
638 	     argv[0], argc-1);
639       return STAT_NORETRY;
640    }
641 
642    pf = strtoul(pfname, &garbage, 0);
643    if (*garbage != '\0') {
644       Warn1("garbage in parameter: \"%s\"", garbage);
645    }
646 
647    retropt_socket_pf(opts, &pf);
648    /*retropt_int(opts, OPT_IP_PROTOCOL, &proto);*/
649    xfd->howtoend = END_SHUTDOWN;
650 
651    xfd->peersa.soa.sa_family = pf;
652    themsize = 0;
653    if ((result =
654 	dalan(address, (uint8_t *)&xfd->peersa.soa.sa_data, &themsize,
655 	      sizeof(xfd->peersa), 'i'))
656        < 0) {
657       Error1("data too long: \"%s\"", address);
658    } else if (result > 0) {
659       Error1("syntax error in \"%s\"", address);
660    }
661    xfd->salen = themsize + sizeof(sa_family_t);
662 #if HAVE_STRUCT_SOCKADDR_SALEN
663    xfd->peersa.soa.sa_len =
664       sizeof(xfd->peersa.soa.sa_len) + sizeof(xfd->peersa.soa.sa_family) +
665       themsize;
666 #endif
667 
668    if ((result =
669 	_xioopen_socket_sendto(pfname, typename, protname, address,
670 			       opts, xioflags, xxfd, groups))
671        != STAT_OK) {
672       return result;
673    }
674 
675    xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
676 
677    xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family;
678 
679    /* which reply sockets will accept - determine by range option */
680    if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
681       if (xioparserange(rangename, 0, &xfd->para.socket.range) < 0) {
682 	 free(rangename);
683 	 return STAT_NORETRY;
684       }
685       xfd->para.socket.dorange = true;
686       xfd->dtype |= XIOREAD_RECV_CHECKRANGE;
687       free(rangename);
688    }
689 
690    _xio_openlate(xfd, opts);
691    return STAT_OK;
692 }
693 
694 #endif /* WITH_GENERICSOCKET */
695 
xiogetpacketinfo(int fd)696 int xiogetpacketinfo(int fd)
697 {
698 #if defined(MSG_ERRQUEUE)
699    int _errno = errno;
700    char peername[256];
701    union sockaddr_union _peername;
702    /* union sockaddr_union _sockname; */
703    union sockaddr_union *pa = &_peername;	/* peer address */
704    /* union sockaddr_union *la = &_sockname; */	/* local address */
705    socklen_t palen = sizeof(_peername);	/* peer address size */
706    char ctrlbuff[1024];			/* ancillary messages */
707    struct msghdr msgh = {0};
708 
709    msgh.msg_name = pa;
710    msgh.msg_namelen = palen;
711 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
712    msgh.msg_control = ctrlbuff;
713 #endif
714 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
715    msgh.msg_controllen = sizeof(ctrlbuff);
716 #endif
717    if (xiogetpacketsrc(fd,
718 		       &msgh,
719 		       MSG_ERRQUEUE
720 #ifdef MSG_TRUNC
721 		       |MSG_TRUNC
722 #endif
723 		       ) >= 0
724        ) {
725       palen = msgh.msg_namelen;
726 
727       Notice1("receiving packet from %s"/*"src"*/,
728 	      sockaddr_info(&pa->soa, palen, peername, sizeof(peername))/*,
729 									  sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
730 
731       xiodopacketinfo(&msgh, true, true);
732    }
733    errno = _errno;
734 #endif /* defined(MSG_ERRQUEUE) */
735    return 0;
736 }
737 
738 
739 
740 /* a subroutine that is common to all socket addresses that want to connect
741    to a peer address.
742    might fork.
743    applies and consumes the following options:
744    PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
745    PH_CONNECTED, PH_LATE,
746    OFUNC_OFFSET,
747    OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
748    returns 0 on success.
749 */
_xioopen_connect(struct single * xfd,union sockaddr_union * us,size_t uslen,struct sockaddr * them,size_t themlen,struct opt * opts,int pf,int socktype,int protocol,bool alt,int level)750 int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
751 		     struct sockaddr *them, size_t themlen,
752 		     struct opt *opts, int pf, int socktype, int protocol,
753 		     bool alt, int level) {
754    int fcntl_flags = 0;
755    char infobuff[256];
756    union sockaddr_union la;
757    socklen_t lalen = themlen;
758    int _errno;
759    int result;
760 
761 #if WITH_UNIX
762    if (pf == PF_UNIX && us != NULL) {
763       applyopts_named(us->un.sun_path, opts, PH_EARLY);
764    }
765 #endif
766 
767    if ((xfd->fd = xiosocket(opts, pf, socktype, protocol, level)) < 0) {
768       return STAT_RETRYLATER;
769    }
770 
771    applyopts_offset(xfd, opts);
772    applyopts(xfd->fd, opts, PH_PASTSOCKET);
773    applyopts(xfd->fd, opts, PH_FD);
774 
775    applyopts_cloexec(xfd->fd, opts);
776 
777 #if WITH_UNIX
778    if (pf == PF_UNIX && us != NULL) {
779       applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
780    }
781 #endif
782    applyopts(xfd->fd, opts, PH_PREBIND);
783    applyopts(xfd->fd, opts, PH_BIND);
784 #if WITH_TCP || WITH_UDP
785    if (alt) {
786       union sockaddr_union sin, *sinp;
787       unsigned short *port, i, N;
788       div_t dv;
789 
790       /* prepare sockaddr for bind probing */
791       if (us) {
792 	 sinp = us;
793       } else {
794 	 if (them->sa_family == AF_INET) {
795 	    socket_in_init(&sin.ip4);
796 #if WITH_IP6
797 	 } else {
798 	    socket_in6_init(&sin.ip6);
799 #endif
800 	 }
801 	 sinp = &sin;
802       }
803       if (them->sa_family == AF_INET) {
804 	 port = &sin.ip4.sin_port;
805 #if WITH_IP6
806       } else if (them->sa_family == AF_INET6) {
807 	 port = &sin.ip6.sin6_port;
808 #endif
809       } else {
810 	 port = 0;	/* just to make compiler happy */
811       }
812       /* combine random+step variant to quickly find a free port when only
813 	 few are in use, and certainly find a free port in defined time even
814 	 if there are almost all in use */
815       /* dirt 1: having tcp/udp code in socket function */
816       /* dirt 2: using a time related system call for init of random */
817       {
818 	 /* generate a random port, with millisecond random init */
819 #if 0
820 	 struct timeb tb;
821 	 ftime(&tb);
822 	 srandom(tb.time*1000+tb.millitm);
823 #else
824 	 struct timeval tv;
825 	 struct timezone tz;
826 	 tz.tz_minuteswest = 0;
827 	 tz.tz_dsttime = 0;
828 	 if ((result = Gettimeofday(&tv, &tz)) < 0) {
829 	    Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno));
830 	 }
831 	 srandom(tv.tv_sec*1000000+tv.tv_usec);
832 #endif
833       }
834       dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER);
835       i = N = XIO_IPPORT_LOWER + dv.rem;
836       do {	/* loop over lowport bind() attempts */
837 	 *port = htons(i);
838 	 if (Bind(xfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
839 	    Msg4(errno==EADDRINUSE?E_INFO:level,
840 		 "bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
841 		 sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
842 		 sizeof(*sinp), strerror(errno));
843 	    if (errno != EADDRINUSE) {
844 	       Close(xfd->fd);
845 	       return STAT_RETRYLATER;
846 	    }
847 	 } else {
848 	    break;	/* could bind to port, good, continue past loop */
849 	 }
850 	 --i;  if (i < XIO_IPPORT_LOWER)  i = IPPORT_RESERVED-1;
851 	 if (i == N) {
852 	    Msg(level, "no low port available");
853 	    /*errno = EADDRINUSE; still assigned */
854 	    Close(xfd->fd);
855 	    return STAT_RETRYLATER;
856 	 }
857       } while (i != N);
858    } else
859 #endif /* WITH_TCP || WITH_UDP */
860 
861    if (us) {
862 #if WITH_UNIX
863       if (pf == PF_UNIX && us != NULL) {
864 	 applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
865       }
866 #endif
867       if (Bind(xfd->fd, &us->soa, uslen) < 0) {
868 	 Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
869 	      xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
870 	      uslen, strerror(errno));
871 	 Close(xfd->fd);
872 	 return STAT_RETRYLATER;
873       }
874    }
875 #if WITH_UNIX
876    if (pf == PF_UNIX && us != NULL) {
877       applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
878    }
879 #endif
880 
881    applyopts(xfd->fd, opts, PH_PASTBIND);
882 
883    applyopts(xfd->fd, opts, PH_CONNECT);
884 
885    if (xfd->para.socket.connect_timeout.tv_sec  != 0 ||
886        xfd->para.socket.connect_timeout.tv_usec != 0) {
887       fcntl_flags = Fcntl(xfd->fd, F_GETFL);
888       Fcntl_l(xfd->fd, F_SETFL, fcntl_flags|O_NONBLOCK);
889    }
890 
891    result = Connect(xfd->fd, them, themlen);
892    _errno = errno;
893    la.soa.sa_family = them->sa_family;  lalen = sizeof(la);
894    if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) {
895       Msg4(level-1, "getsockname(%d, %p, {%d}): %s",
896 	    xfd->fd, &la.soa, lalen, strerror(errno));
897    }
898    errno = _errno;
899    if (result < 0) {
900       if (errno == EINPROGRESS) {
901 	 if (xfd->para.socket.connect_timeout.tv_sec  != 0 ||
902 	     xfd->para.socket.connect_timeout.tv_usec != 0) {
903 	    struct timeval timeout;
904 	    struct pollfd writefd;
905 	    int result;
906 
907 	    Info4("connect(%d, %s, "F_Zd"): %s",
908 		  xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
909 		  themlen, strerror(errno));
910 	    timeout = xfd->para.socket.connect_timeout;
911 	    writefd.fd = xfd->fd;
912 	    writefd.events = (POLLOUT|POLLERR);
913 	    result = xiopoll(&writefd, 1, &timeout);
914 	    if (result < 0) {
915 	       Msg4(level, "xiopoll({%d,POLLOUT|POLLERR},,{"F_tv_sec"."F_tv_usec"): %s",
916 		    xfd->fd, timeout.tv_sec, timeout.tv_usec, strerror(errno));
917 	       return STAT_RETRYLATER;
918 	    }
919 	    if (result == 0) {
920 	       Msg2(level, "connecting to %s: %s",
921 		    sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
922 		    strerror(ETIMEDOUT));
923 	       return STAT_RETRYLATER;
924 	    }
925 	    if (writefd.revents & POLLERR) {
926 #if 0
927 	       unsigned char dummy[1];
928 	       Read(xfd->fd, &dummy, 1);	/* get error message */
929 	       Msg2(level, "connecting to %s: %s",
930 		    sockaddr_info(them, infobuff, sizeof(infobuff)),
931 		    strerror(errno));
932 #else
933 	       Connect(xfd->fd, them, themlen);	/* get error message */
934 	       Msg4(level, "connect(%d, %s, "F_Zd"): %s",
935 		     xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
936 		     themlen, strerror(errno));
937 #endif
938 	       return STAT_RETRYLATER;
939 	    }
940 	    /* otherwise OK */
941 	    Fcntl_l(xfd->fd, F_SETFL, fcntl_flags);
942 	 } else {
943 	    Warn4("connect(%d, %s, "F_Zd"): %s",
944 		  xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
945 		  themlen, strerror(errno));
946 	 }
947       } else if (pf == PF_UNIX && errno == EPROTOTYPE) {
948 	 /* this is for UNIX domain sockets: a connect attempt seems to be
949 	    the only way to distinguish stream and datagram sockets */
950 	 int _errno = errno;
951 	 Info4("connect(%d, %s, "F_Zd"): %s",
952 	       xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
953 	       themlen, strerror(errno));
954 #if 0
955 	 Info("assuming datagram socket");
956 	 xfd->dtype = DATA_RECVFROM;
957 	 xfd->salen = themlen;
958 	 memcpy(&xfd->peersa.soa, them, xfd->salen);
959 #endif
960 	 /*!!! and remove bind socket */
961 	 Close(xfd->fd);  xfd->fd = -1;
962 	 errno = _errno;
963 	 return -1;
964       } else {
965 	 /* try to find details about error, especially from ICMP */
966 	 xiogetpacketinfo(xfd->fd);
967 
968 	 /* continue mainstream */
969 	 Msg4(level, "connect(%d, %s, "F_Zd"): %s",
970 	      xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
971 	      themlen, strerror(errno));
972 	 Close(xfd->fd);
973 	 return STAT_RETRYLATER;
974       }
975    } else {	/* result >= 0 */
976       Notice1("successfully connected from local address %s",
977 	      sockaddr_info(&la.soa, themlen, infobuff, sizeof(infobuff)));
978    }
979 
980    applyopts_fchown(xfd->fd, opts);	/* OPT_USER, OPT_GROUP */
981    applyopts(xfd->fd, opts, PH_CONNECTED);
982 #if WITH_UNIX
983    if (pf == PF_UNIX && us != NULL) {
984       applyopts_named(us->un.sun_path, opts, PH_LATE);
985    }
986 #endif
987    applyopts(xfd->fd, opts, PH_LATE);
988 
989    return STAT_OK;
990 }
991 
992 
993 /* a subroutine that is common to all socket addresses that want to connect
994    to a peer address.
995    might fork.
996    applies and consumes the following option:
997    PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
998    PH_CONNECTED, PH_LATE,
999    OFUNC_OFFSET,
1000    OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
1001    returns 0 on success.
1002 */
xioopen_connect(struct single * xfd,union sockaddr_union * us,size_t uslen,struct sockaddr * them,size_t themlen,struct opt * opts,int pf,int socktype,int protocol,bool alt)1003 int xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
1004 		    struct sockaddr *them, size_t themlen,
1005 		    struct opt *opts, int pf, int socktype, int protocol,
1006 		    bool alt) {
1007    bool dofork = false;
1008    struct opt *opts0;
1009    char infobuff[256];
1010    int level;
1011    int result;
1012 
1013    retropt_bool(opts, OPT_FORK, &dofork);
1014 
1015    opts0 = copyopts(opts, GROUP_ALL);
1016 
1017    Notice1("opening connection to %s",
1018 	   sockaddr_info(them, themlen, infobuff, sizeof(infobuff)));
1019 
1020    do {	/* loop over retries and forks */
1021 
1022 #if WITH_RETRY
1023       if (xfd->forever || xfd->retry) {
1024 	 level = E_INFO;
1025       } else
1026 #endif /* WITH_RETRY */
1027 	 level = E_ERROR;
1028       result =
1029 	 _xioopen_connect(xfd, us, uslen, them, themlen, opts,
1030 			  pf, socktype, protocol, alt, level);
1031       switch (result) {
1032       case STAT_OK: break;
1033 #if WITH_RETRY
1034       case STAT_RETRYLATER:
1035 	 if (xfd->forever || xfd->retry) {
1036 	    --xfd->retry;
1037 	    if (result == STAT_RETRYLATER) {
1038 	       Nanosleep(&xfd->intervall, NULL);
1039 	    }
1040 	    dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
1041 	    continue;
1042 	 }
1043 	 return STAT_NORETRY;
1044 #endif /* WITH_RETRY */
1045       default:
1046 	 return result;
1047       }
1048 
1049       if (dofork) {
1050 	 xiosetchilddied();	/* set SIGCHLD handler */
1051       }
1052 
1053 #if WITH_RETRY
1054       if (dofork) {
1055 	 pid_t pid;
1056 	 int level = E_ERROR;
1057 	 if (xfd->forever || xfd->retry) {
1058 	    level = E_WARN;	/* most users won't expect a problem here,
1059 				   so Notice is too weak */
1060 	 }
1061 
1062 	 while ((pid = xio_fork(false, level)) < 0) {
1063 	    --xfd->retry;
1064 	    if (xfd->forever || xfd->retry) {
1065 	       dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
1066 	       Nanosleep(&xfd->intervall, NULL); continue;
1067 	    }
1068 	    return STAT_RETRYLATER;
1069 	 }
1070 
1071 	 if (pid == 0) {	/* child process */
1072 	    break;
1073 	 }
1074 
1075 	 /* parent process */
1076 	 Close(xfd->fd);
1077 	 /* with and without retry */
1078 	 Nanosleep(&xfd->intervall, NULL);
1079 	 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
1080 	 continue;	/* with next socket() bind() connect() */
1081       } else
1082 #endif /* WITH_RETRY */
1083       {
1084 	 break;
1085       }
1086 #if 0
1087       if ((result = _xio_openlate(fd, opts)) < 0)
1088 	 return result;
1089 #endif
1090    } while (true);
1091 
1092    return 0;
1093 }
1094 
1095 
1096 /* common to xioopen_udp_sendto, ..unix_sendto, ..rawip
1097    applies and consumes the following option:
1098    PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
1099    OFUNC_OFFSET
1100    OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
1101  */
_xioopen_dgram_sendto(union sockaddr_union * us,socklen_t uslen,struct opt * opts,int xioflags,xiosingle_t * xfd,unsigned groups,int pf,int socktype,int ipproto)1102 int _xioopen_dgram_sendto(/* them is already in xfd->peersa */
1103 			union sockaddr_union *us, socklen_t uslen,
1104 			struct opt *opts,
1105 			int xioflags, xiosingle_t *xfd, unsigned groups,
1106 			int pf, int socktype, int ipproto) {
1107    int level = E_ERROR;
1108    union sockaddr_union la; socklen_t lalen = sizeof(la);
1109    char infobuff[256];
1110 
1111 #if WITH_UNIX
1112    if (pf == PF_UNIX && us != NULL) {
1113       applyopts_named(us->un.sun_path, opts, PH_EARLY);
1114    }
1115 #endif
1116 
1117    if ((xfd->fd = xiosocket(opts, pf, socktype, ipproto, level)) < 0) {
1118       return STAT_RETRYLATER;
1119    }
1120 
1121    applyopts_offset(xfd, opts);
1122    applyopts_single(xfd, opts, PH_PASTSOCKET);
1123    applyopts(xfd->fd, opts, PH_PASTSOCKET);
1124    applyopts(xfd->fd, opts, PH_FD);
1125 
1126    applyopts_cloexec(xfd->fd, opts);
1127 
1128 #if WITH_UNIX
1129    if (pf == PF_UNIX && us != NULL) {
1130       applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
1131    }
1132 #endif
1133    applyopts(xfd->fd, opts, PH_PREBIND);
1134    applyopts(xfd->fd, opts, PH_BIND);
1135 
1136    if (us) {
1137       if (Bind(xfd->fd, &us->soa, uslen) < 0) {
1138 	 Msg4(level, "bind(%d, {%s}, "F_socklen"): %s",
1139 	      xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
1140 	      uslen, strerror(errno));
1141 	 Close(xfd->fd);
1142 	 return STAT_RETRYLATER;
1143       }
1144    }
1145 #if WITH_UNIX
1146    if (pf == PF_UNIX && us != NULL) {
1147       applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
1148    }
1149 #endif
1150 
1151    applyopts(xfd->fd, opts, PH_PASTBIND);
1152 
1153    /*applyopts(xfd->fd, opts, PH_CONNECT);*/
1154 
1155    if (Getsockname(xfd->fd, &la.soa, &lalen) < 0) {
1156       Warn4("getsockname(%d, %p, {%d}): %s",
1157 	    xfd->fd, &la.soa, lalen, strerror(errno));
1158    }
1159 
1160    applyopts_fchown(xfd->fd, opts);
1161    applyopts(xfd->fd, opts, PH_CONNECTED);
1162 #if WITH_UNIX
1163    if (pf == PF_UNIX && us != NULL) {
1164       applyopts_named(us->un.sun_path, opts, PH_LATE);
1165    }
1166 #endif
1167    applyopts(xfd->fd, opts, PH_LATE);
1168 
1169    /* xfd->dtype = DATA_RECVFROM; *//* no, the caller must set this (ev _SKIPIP) */
1170    Notice1("successfully prepared local socket %s",
1171 	   sockaddr_info(&la.soa, lalen, infobuff, sizeof(infobuff)));
1172 
1173    return STAT_OK;
1174 }
1175 
1176 
1177 /* when the recvfrom address (with option fork) receives a packet it keeps this
1178    packet in the IP stacks input queue and forks a sub process. The sub process
1179    then reads this packet for processing its data.
1180    There is a problem because the parent process would find the same packet
1181    again if it calls select()/poll() before the child process reads the
1182    packet.
1183    To solve this problem we implement the following mechanism:
1184    The sub process sends a SIGUSR1 when it has read the packet (or a SIGCHLD if
1185    it dies before). The parent process waits until it receives that signal and
1186    only then continues to listen.
1187    To prevent a signal from another process to trigger our loop, we pass the
1188    pid of the sub process to the signal handler in xio_waitingfor. The signal
1189    handler sets xio_hashappened if the pid matched.
1190 */
1191 static pid_t xio_waitingfor;	/* info from recv loop to signal handler:
1192 				   indicates the pid of the child process
1193 				   that should send us the USR1 signal */
1194 static bool xio_hashappened;	/* info from signal handler to loop: child
1195 				   process has read ("consumed") the packet */
1196 static int xio_childstatus;
1197 
1198 /* this is the signal handler for USR1 and CHLD */
xiosigaction_hasread(int signum,siginfo_t * siginfo,void * ucontext)1199 void xiosigaction_hasread(int signum
1200 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1201 			  , siginfo_t *siginfo, void *ucontext
1202 #endif
1203 			  ) {
1204    pid_t pid;
1205    int _errno;
1206    int status = 0;
1207    bool wassig = false;
1208 
1209    _errno = errno;
1210    diag_in_handler = 1;
1211 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1212    Debug5("xiosigaction_hasread(%d, {%d,%d,%d,"F_pid"}, )",
1213 	  signum, siginfo->si_signo, siginfo->si_errno, siginfo->si_code,
1214 	  siginfo->si_pid);
1215 #else
1216    Debug1("xiosigaction_hasread(%d)", signum);
1217 #endif
1218    if (signum == SIGCHLD) {
1219       do {
1220 	 pid = Waitpid(-1, &status, WNOHANG);
1221 	 if (pid == 0) {
1222 	    Msg(wassig?E_INFO:E_WARN,
1223 		"waitpid(-1, {}, WNOHANG): no child has exited");
1224 	    Info("xiosigaction_hasread() finished");
1225 	    Debug("xiosigaction_hasread() ->");
1226 	    diag_in_handler = 0;
1227 	    errno = _errno;
1228 	    return;
1229 	 } else if (pid < 0 && errno == ECHILD) {
1230 	    Msg(wassig?E_INFO:E_WARN,
1231 		 "waitpid(-1, {}, WNOHANG): "F_strerror);
1232 	    Info("xiosigaction_hasread() finished");
1233 	    Debug("xiosigaction_hasread() ->");
1234 	    diag_in_handler = 0;
1235 	    errno = _errno;
1236 	    return;
1237 	 }
1238 	 wassig = true;
1239 	 if (pid < 0) {
1240 	    Warn1("waitpid(-1, {%d}, WNOHANG): "F_strerror, status);
1241 	    Info("xiosigaction_hasread() finished");
1242 	    Debug("xiosigaction_hasread() ->");
1243 	    diag_in_handler = 0;
1244 	    errno = _errno;
1245 	    return;
1246 	 }
1247 	 if (pid == xio_waitingfor) {
1248 	    xio_hashappened = true;
1249             xio_childstatus = WEXITSTATUS(status);
1250 	    Debug("xiosigaction_hasread() ->");
1251 	    diag_in_handler = 0;
1252 	    errno = _errno;
1253 	    return;
1254 	 }
1255       } while (1);
1256    }
1257 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1258    if (xio_waitingfor == siginfo->si_pid) {
1259       xio_hashappened = true;
1260    }
1261 #else
1262    xio_hashappened = true;
1263 #endif
1264 #if !HAVE_SIGACTION
1265    Signal(sig, xiosigaction_hasread);
1266 #endif /* !HAVE_SIGACTION */
1267    Debug("xiosigaction_hasread() ->");
1268    diag_in_handler = 0;
1269    errno = _errno;
1270    return;
1271 }
1272 
1273 
1274 /* waits for incoming packet, checks its source address and port. Depending
1275    on fork option, it may fork a subprocess.
1276    Returns STAT_OK if a the packet was accepted; with fork option, this is already in
1277    a new subprocess!
1278    Other return values indicate a problem; this can happen in the master
1279    process or in a subprocess.
1280    This function does not retry. If you need retries, handle this is a
1281    loop in the calling function.
1282    after fork, we set the forever/retry of the child process to 0
1283    applies and consumes the following options:
1284    PH_INIT, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD,
1285    PH_CONNECTED, PH_LATE, PH_LATE2
1286    OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, cloexec, OPT_RANGE, tcpwrap
1287  */
_xioopen_dgram_recvfrom(struct single * xfd,int xioflags,struct sockaddr * us,socklen_t uslen,struct opt * opts,int pf,int socktype,int proto,int level)1288 int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
1289 			  struct sockaddr *us, socklen_t uslen,
1290 			  struct opt *opts,
1291 			  int pf, int socktype, int proto, int level) {
1292    char *rangename;
1293    bool dofork = false;
1294    pid_t pid;	/* mostly int; only used with fork */
1295    char infobuff[256];
1296    char lisname[256];
1297    bool drop = false;	/* true if current packet must be dropped */
1298    int result;
1299 
1300    retropt_bool(opts, OPT_FORK, &dofork);
1301 
1302    if (dofork) {
1303       if (!(xioflags & XIO_MAYFORK)) {
1304 	 Error("option fork not allowed here");
1305 	 return STAT_NORETRY;
1306       }
1307       xfd->flags |= XIO_DOESFORK;
1308    }
1309 
1310    if (applyopts_single(xfd, opts, PH_INIT) < 0)  return STAT_NORETRY;
1311 
1312    if ((xfd->fd = xiosocket(opts, pf, socktype, proto, level)) < 0) {
1313       return STAT_RETRYLATER;
1314    }
1315 
1316    applyopts_single(xfd, opts, PH_PASTSOCKET);
1317    applyopts(xfd->fd, opts, PH_PASTSOCKET);
1318 
1319    applyopts_cloexec(xfd->fd, opts);
1320 
1321    applyopts(xfd->fd, opts, PH_PREBIND);
1322    applyopts(xfd->fd, opts, PH_BIND);
1323    if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
1324       Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
1325 	   sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
1326 	   strerror(errno));
1327       Close(xfd->fd);
1328       return STAT_RETRYLATER;
1329    }
1330 
1331 #if WITH_UNIX
1332    if (pf == AF_UNIX && us != NULL) {
1333       applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
1334    }
1335 #endif
1336 
1337    applyopts(xfd->fd, opts, PH_PASTBIND);
1338 #if WITH_UNIX
1339    if (pf == AF_UNIX && us != NULL) {
1340       /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
1341       applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
1342       applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
1343    }
1344 #endif /* WITH_UNIX */
1345 
1346    /* for generic sockets, this has already been retrieved */
1347    if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
1348       if (xioparserange(rangename, pf, &xfd->para.socket.range)
1349 	  < 0) {
1350 	 free(rangename);
1351 	 return STAT_NORETRY;
1352       }
1353       free(rangename);
1354       xfd->para.socket.dorange = true;
1355    }
1356 
1357 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1358    xio_retropt_tcpwrap(xfd, opts);
1359 #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1360 
1361    if (xioopts.logopt == 'm') {
1362       Info("starting recvfrom loop, switching to syslog");
1363       diag_set('y', xioopts.syslogfac);  xioopts.logopt = 'y';
1364    } else {
1365       Info("starting recvfrom loop");
1366    }
1367 
1368    if (dofork) {
1369 #if HAVE_SIGACTION
1370    {
1371       struct sigaction act;
1372       memset(&act, 0, sizeof(struct sigaction));
1373       act.sa_flags   = SA_NOCLDSTOP/*|SA_RESTART*/
1374 #ifdef SA_SIGINFO /* not on Linux 2.0(.33) */
1375 	 |SA_SIGINFO
1376 #endif
1377 #ifdef SA_NOMASK
1378          |SA_NOMASK
1379 #endif
1380          ;
1381 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
1382       act.sa_sigaction = xiosigaction_hasread;
1383 #else /* Linux 2.0(.33) does not have sigaction.sa_sigaction */
1384       act.sa_handler = xiosigaction_hasread;
1385 #endif
1386       sigfillset(&act.sa_mask);
1387       if (Sigaction(SIGUSR1, &act, NULL) < 0) {
1388          /*! Linux man does not explicitely say that errno is defined */
1389          Warn1("sigaction(SIGUSR1, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno));
1390       }
1391       if (Sigaction(SIGCHLD, &act, NULL) < 0) {
1392          /*! Linux man does not explicitely say that errno is defined */
1393          Warn1("sigaction(SIGCHLD, {&xiosigaction_subaddr_ok}, NULL): %s", strerror(errno));
1394       }
1395    }
1396 #else /* !HAVE_SIGACTION */
1397    /*!!!*/
1398       if (Signal(SIGUSR1, xiosigaction_hasread) == SIG_ERR) {
1399 	 Warn1("signal(SIGUSR1, xiosigaction_hasread): %s", strerror(errno));
1400       }
1401       if (Signal(SIGCHLD, xiosigaction_hasread) == SIG_ERR) {
1402 	 Warn1("signal(SIGCHLD, xiosigaction_hasread): %s", strerror(errno));
1403       }
1404 #endif /* !HAVE_SIGACTION */
1405    }
1406 
1407    while (true) {	/* but we only loop if fork option is set */
1408       char peername[256];
1409       union sockaddr_union _peername;
1410       union sockaddr_union _sockname;
1411       union sockaddr_union *pa = &_peername;	/* peer address */
1412       union sockaddr_union *la = &_sockname;	/* local address */
1413       socklen_t palen = sizeof(_peername);	/* peer address size */
1414       char ctrlbuff[1024];			/* ancillary messages */
1415       struct msghdr msgh = {0};
1416 
1417       socket_init(pf, pa);
1418 
1419       if (drop) {
1420 	 char *dummy[2];
1421 
1422 	 Recv(xfd->fd, dummy, sizeof(dummy), 0);
1423 	 drop = true;
1424       }
1425 
1426       /* loop until select()/poll() returns valid */
1427       do {
1428 	 struct pollfd readfd;
1429 	 /*? int level = E_ERROR;*/
1430 	 if (us != NULL) {
1431 	    Notice1("receiving on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
1432 	 } else {
1433 	    Notice1("receiving IP protocol %u", proto);
1434 	 }
1435 	 readfd.fd = xfd->fd;
1436 	 readfd.events = POLLIN;
1437 	 if (xiopoll(&readfd, 1, NULL) > 0) {
1438 	    break;
1439 	 }
1440 
1441 	 if (errno == EINTR) {
1442 	    continue;
1443 	 }
1444 
1445 	 Msg2(level, "poll({%d,,},,-1): %s", xfd->fd, strerror(errno));
1446 	 Close(xfd->fd);
1447 	 return STAT_RETRYLATER;
1448       } while (true);
1449 
1450       msgh.msg_name = pa;
1451       msgh.msg_namelen = palen;
1452 #if HAVE_STRUCT_MSGHDR_MSGCONTROL
1453       msgh.msg_control = ctrlbuff;
1454 #endif
1455 #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
1456       msgh.msg_controllen = sizeof(ctrlbuff);
1457 #endif
1458       if (xiogetpacketsrc(xfd->fd,
1459 			  &msgh,
1460 			  MSG_PEEK
1461 #ifdef MSG_TRUNC
1462 			  |MSG_TRUNC
1463 #endif
1464 			  ) < 0) {
1465 	 return STAT_RETRYLATER;
1466       }
1467       palen = msgh.msg_namelen;
1468 
1469       Notice1("receiving packet from %s"/*"src"*/,
1470 	      sockaddr_info(&pa->soa, palen, peername, sizeof(peername))/*,
1471 							     sockaddr_info(&la->soa, sockname, sizeof(sockname))*/);
1472 
1473       xiodopacketinfo(&msgh, true, true);
1474 
1475       if (xiocheckpeer(xfd, pa, la) < 0) {
1476 	 /* drop packet */
1477 	 char buff[512];
1478 	 Recv(xfd->fd, buff, sizeof(buff), 0);
1479 	 continue;
1480       }
1481       Info1("permitting packet from %s",
1482 	    sockaddr_info(&pa->soa, palen,
1483 			  infobuff, sizeof(infobuff)));
1484 
1485       /* set the env vars describing the local and remote sockets */
1486       /*xiosetsockaddrenv("SOCK", la, lalen, proto);*/
1487       xiosetsockaddrenv("PEER", pa, palen, proto);
1488 
1489       applyopts(xfd->fd, opts, PH_FD);
1490 
1491       applyopts(xfd->fd, opts, PH_CONNECTED);
1492 
1493       xfd->peersa = *(union sockaddr_union *)pa;
1494       xfd->salen = palen;
1495 
1496       if (dofork) {
1497 	 sigset_t oldset, mask_sigchldusr1;
1498 
1499 	 /* we must prevent that the current packet triggers another fork;
1500 	    therefore we wait for a signal from the recent child: USR1
1501 	    indicates that is has consumed the last packet; CHLD means it has
1502 	    terminated */
1503 	 /* block SIGCHLD and SIGUSR1 until parent is ready to react */
1504 	 Sigprocmask(SIG_BLOCK, NULL, &mask_sigchldusr1);
1505 	 sigaddset(&mask_sigchldusr1, SIGCHLD);
1506 	 sigaddset(&mask_sigchldusr1, SIGUSR1);
1507 	 Sigprocmask(SIG_SETMASK, &mask_sigchldusr1, &oldset);
1508 
1509 	 if ((pid = xio_fork(false, level)) < 0) {
1510 	    Close(xfd->fd);
1511 	    Sigprocmask(SIG_SETMASK, &oldset, NULL);
1512 	    return STAT_RETRYLATER;
1513 	 }
1514 
1515 	 if (pid == 0) {	/* child */
1516 	    /* no reason to block SIGCHLD in child process */
1517 	    Sigprocmask(SIG_SETMASK, &oldset, NULL);
1518 	    xfd->ppid = Getppid();	/* send parent a signal when packet has
1519 					   been consumed */
1520 
1521 #if WITH_RETRY
1522 	    /* !? */
1523 	    xfd->retry = 0;
1524 	    xfd->forever = 0;
1525 	    level = E_ERROR;
1526 #endif /* WITH_RETRY */
1527 
1528 #if WITH_UNIX
1529 	    /* with UNIX sockets: only listening parent is allowed to remove
1530 	       the socket file */
1531 	    xfd->opt_unlink_close = false;
1532 #endif /* WITH_UNIX */
1533 
1534 	    break;
1535 	 }
1536 
1537 	 /* server: continue loop with listen */
1538 	 xio_waitingfor = pid;
1539 
1540 #if HAVE_PSELECT
1541 	 {
1542 	    struct timespec timeout = { LONG_MAX, 0 };
1543 	    Pselect(0, NULL, NULL, NULL, &timeout, &oldset);
1544 	    Sigprocmask(SIG_SETMASK, &oldset, NULL);
1545 	 }
1546 #else /* ! HAVE_PSELECT */
1547 	 /* now we are ready to handle signals */
1548 	 Sigprocmask(SIG_SETMASK, &oldset, NULL);
1549 
1550 	 while (!xio_hashappened) {
1551 	    Sleep(1);	/* any signal speeds up return */
1552 	 }
1553 #endif /* ! HAVE_PSELECT */
1554 	 xio_waitingfor = 0;	/* so this child will not set hashappened again */
1555 	 xio_hashappened = false;
1556 
1557          if (xio_childstatus != 0) {
1558              char buff[512];
1559              Recv(xfd->fd, buff, sizeof(buff), 0);
1560              xio_childstatus = 0;
1561              Info("drop data because of child exit failed");
1562          }
1563 	 Info("continue listening");
1564       } else {
1565 	break;
1566       }
1567    }
1568    if ((result = _xio_openlate(xfd, opts)) != 0)
1569       return STAT_NORETRY;
1570 
1571    return STAT_OK;
1572 }
1573 
1574 
1575 /* returns STAT_* */
_xioopen_dgram_recv(struct single * xfd,int xioflags,struct sockaddr * us,socklen_t uslen,struct opt * opts,int pf,int socktype,int proto,int level)1576 int _xioopen_dgram_recv(struct single *xfd, int xioflags,
1577 			struct sockaddr *us, socklen_t uslen,
1578 			struct opt *opts, int pf, int socktype, int proto,
1579 			int level) {
1580    char *rangename;
1581    char infobuff[256];
1582 
1583    if (applyopts_single(xfd, opts, PH_INIT) < 0)  return STAT_NORETRY;
1584 
1585    if ((xfd->fd = xiosocket(opts, pf, socktype, proto, level)) < 0) {
1586       return STAT_RETRYLATER;
1587    }
1588 
1589    applyopts_single(xfd, opts, PH_PASTSOCKET);
1590    applyopts(xfd->fd, opts, PH_PASTSOCKET);
1591 
1592    applyopts_cloexec(xfd->fd, opts);
1593 
1594    applyopts(xfd->fd, opts, PH_PREBIND);
1595    applyopts(xfd->fd, opts, PH_BIND);
1596    if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
1597       Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
1598 	   sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
1599 	   strerror(errno));
1600       Close(xfd->fd);
1601       return STAT_RETRYLATER;
1602    }
1603 
1604 #if WITH_UNIX
1605    if (pf == AF_UNIX && us != NULL) {
1606       applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
1607    }
1608 #endif
1609 
1610    applyopts_single(xfd, opts, PH_PASTBIND);
1611    applyopts(xfd->fd, opts, PH_PASTBIND);
1612 #if WITH_UNIX
1613    if (pf == AF_UNIX && us != NULL) {
1614       /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
1615       applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
1616       applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
1617    }
1618 #endif /* WITH_UNIX */
1619 
1620 #if WITH_IP4 /*|| WITH_IP6*/
1621    if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
1622       if (xioparserange(rangename, pf, &xfd->para.socket.range)
1623 	  < 0) {
1624 	 free(rangename);
1625 	 return STAT_NORETRY;
1626       }
1627       free(rangename);
1628       xfd->para.socket.dorange = true;
1629    }
1630 #endif
1631 
1632 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1633    xio_retropt_tcpwrap(xfd, opts);
1634 #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1635 
1636    if (xioopts.logopt == 'm') {
1637       Info("starting recvfrom loop, switching to syslog");
1638       diag_set('y', xioopts.syslogfac);  xioopts.logopt = 'y';
1639    } else {
1640       Info("starting recvfrom loop");
1641    }
1642 
1643    return STAT_OK;
1644 }
1645 
1646 
retropt_socket_pf(struct opt * opts,int * pf)1647 int retropt_socket_pf(struct opt *opts, int *pf) {
1648    char *pfname;
1649 
1650    if (retropt_string(opts, OPT_PROTOCOL_FAMILY, &pfname) >= 0) {
1651       if (isdigit(pfname[0])) {
1652 	 *pf = strtoul(pfname, NULL /*!*/, 0);
1653 #if WITH_IP4
1654       } else if (!strcasecmp("inet", pfname) ||
1655 	  !strcasecmp("inet4", pfname) ||
1656 	  !strcasecmp("ip4", pfname) ||
1657 	  !strcasecmp("ipv4", pfname) ||
1658 	  !strcasecmp("2", pfname)) {
1659 	 *pf = PF_INET;
1660 #endif /* WITH_IP4 */
1661 #if WITH_IP6
1662       } else if (!strcasecmp("inet6", pfname) ||
1663 		 !strcasecmp("ip6", pfname) ||
1664 		 !strcasecmp("ipv6", pfname) ||
1665 		 !strcasecmp("10", pfname)) {
1666 	 *pf = PF_INET6;
1667 #endif /* WITH_IP6 */
1668       } else {
1669 	 Error1("unknown protocol family \"%s\"", pfname);
1670 	 /*! Warn("falling back to INET");*/
1671       }
1672       free(pfname);
1673       return 0;
1674    }
1675    return -1;
1676 }
1677 
1678 
1679 /* this function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
1680    the arriving packet. in msgh the msg_name pointer must refer to an (empty)
1681    sockaddr storage. */
xiogetpacketsrc(int fd,struct msghdr * msgh,int flags)1682 int xiogetpacketsrc(int fd, struct msghdr *msgh, int flags) {
1683    char peekbuff[1];
1684 #if HAVE_STRUCT_IOVEC
1685    struct iovec iovec;
1686 #endif
1687 
1688 #if HAVE_STRUCT_IOVEC
1689    iovec.iov_base = peekbuff;
1690    iovec.iov_len  = sizeof(peekbuff);
1691    msgh->msg_iov = &iovec;
1692    msgh->msg_iovlen = 1;
1693 #endif
1694 #if HAVE_STRUCT_MSGHDR_MSGFLAGS
1695    msgh->msg_flags = 0;
1696 #endif
1697    if (Recvmsg(fd, msgh, flags) < 0) {
1698       Warn1("recvmsg(): %s", strerror(errno));
1699       return STAT_RETRYLATER;
1700    }
1701    return STAT_OK;
1702 }
1703 
1704 
1705 /* works through the ancillary messages found in the given socket header record
1706    and logs the relevant information (E_DEBUG, E_INFO).
1707    calls protocol/layer specific functions for handling the messages
1708    creates appropriate environment vars if withenv is set */
xiodopacketinfo(struct msghdr * msgh,bool withlog,bool withenv)1709 int xiodopacketinfo(struct msghdr *msgh, bool withlog, bool withenv) {
1710 #if defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)
1711    struct cmsghdr *cmsg;
1712 
1713    /* parse ancillary messages */
1714    cmsg = CMSG_FIRSTHDR(msgh);
1715    while (cmsg != NULL) {
1716       int num = 0;	/* number of data components of a ancill.msg */
1717       int i;
1718       char typbuff[16],  *typp;
1719       char nambuff[128], *namp;
1720       char valbuff[256], *valp;
1721       char envbuff[256], *envp;
1722 
1723       if (withlog) {
1724 	 xiodump(CMSG_DATA(cmsg),
1725 		 cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg),
1726 		 valbuff, sizeof(valbuff)-1, 0);
1727 	 Debug4("ancillary message: len="F_cmsg_len", level=%d, type=%d, data=%s",
1728 		cmsg->cmsg_len, cmsg->cmsg_level, cmsg->cmsg_type,
1729 		valbuff);
1730       }
1731 
1732       /* try to get the anc.msg. contents in handy components, protocol/level
1733 	 dependent */
1734       switch (cmsg->cmsg_level) {
1735       case SOL_SOCKET:
1736 	 xiolog_ancillary_socket(cmsg, &num, typbuff, sizeof(typbuff)-1,
1737 				 nambuff, sizeof(nambuff)-1,
1738 				 envbuff, sizeof(envbuff)-1,
1739 				 valbuff, sizeof(valbuff)-1);
1740 	 break;
1741 #if WITH_IP4 || WITH_IP6
1742       case SOL_IP:
1743 	 xiolog_ancillary_ip(cmsg, &num, typbuff, sizeof(typbuff)-1,
1744 			     nambuff, sizeof(nambuff)-1,
1745 			     envbuff, sizeof(envbuff)-1,
1746 			     valbuff, sizeof(valbuff)-1);
1747 	 break;
1748 #endif /* WITH_IP4 || WITH_IP6 */
1749 #if WITH_IP6
1750       case SOL_IPV6:
1751 	 xiolog_ancillary_ip6(cmsg, &num, typbuff, sizeof(typbuff)-1,
1752 			      nambuff, sizeof(nambuff)-1,
1753 			      envbuff, sizeof(envbuff)-1,
1754 			      valbuff, sizeof(valbuff)-1);
1755 	 break;
1756 #endif /* WITH_IP6 */
1757       default:
1758 	 num = 1;
1759 	 snprintf(typbuff, sizeof(typbuff)-1, "LEVEL%u", cmsg->cmsg_level);
1760 	 snprintf(nambuff, sizeof(nambuff)-1, "type%u", cmsg->cmsg_type);
1761 	 xiodump(CMSG_DATA(cmsg),
1762 		 cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg),
1763 		 valbuff, sizeof(valbuff)-1, 0);
1764       }
1765       /* here the info is in typbuff (one string), nambuff (num consecutive
1766 	 strings), and valbuff (num consecutive strings) */
1767       i = 0;
1768       typp = typbuff;  namp = nambuff;  envp = envbuff;  valp = valbuff;
1769       while (i < num) {
1770 	 if (withlog) {
1771 	    Info3("ancillary message: %s: %s=%s", typp, namp, valp);
1772 	 }
1773 	 if (withenv) {
1774 	    if (*envp) {
1775 	       xiosetenv(envp, valp, 1, NULL);
1776 	    } else if (!strcasecmp(typp+strlen(typp)-strlen(namp), namp)) {
1777 	       xiosetenv(typp, valp, 1, NULL);
1778 	    } else	{
1779 	       xiosetenv2(typp, namp, valp, 1, NULL);
1780 	    }
1781 	 }
1782 	 if (++i == num)  break;
1783 	 namp = strchr(namp, '\0')+1;
1784 	 envp = strchr(envp, '\0')+1;
1785 	 valp = strchr(valp, '\0')+1;
1786       }
1787       cmsg = CMSG_NXTHDR(msgh, cmsg);
1788    }
1789    return 0;
1790 #else /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
1791    return -1;
1792 #endif /* !(defined(HAVE_STRUCT_CMSGHDR) && defined(CMSG_DATA)) */
1793 }
1794 
1795 
1796 /* check if peer address is within permitted range.
1797    return >= 0 if so. */
xiocheckrange(union sockaddr_union * sa,struct xiorange * range)1798 int xiocheckrange(union sockaddr_union *sa, struct xiorange *range) {
1799    switch (sa->soa.sa_family) {
1800 #if WITH_IP4
1801    case PF_INET:
1802       return
1803 	 xiocheckrange_ip4(&sa->ip4, range);
1804 #endif /* WITH_IP4 */
1805 #if WITH_IP6
1806    case PF_INET6:
1807       return
1808 	 xiocheckrange_ip6(&sa->ip6, range);
1809 #endif /* WITH_IP6 */
1810 #if 0
1811    case PF_UNSPEC:
1812      {
1813       socklen_t i;
1814       for (i = 0; i < sizeof(sa->soa.sa_data); ++i) {
1815 	 if ((range->netmask.soa.sa_data[i] & sa->soa.sa_data[i]) != range->netaddr.soa.sa_data[i]) {
1816 	    return -1;
1817 	 }
1818       }
1819       return 0;
1820      }
1821 #endif
1822    }
1823    return -1;
1824 }
1825 
xiocheckpeer(xiosingle_t * xfd,union sockaddr_union * pa,union sockaddr_union * la)1826 int xiocheckpeer(xiosingle_t *xfd,
1827 		 union sockaddr_union *pa, union sockaddr_union *la) {
1828    char infobuff[256];
1829    int result;
1830 
1831 #if WITH_IP4
1832    if (xfd->para.socket.dorange) {
1833       if (pa == NULL)  { return -1; }
1834       if (xiocheckrange(pa, &xfd->para.socket.range) < 0) {
1835 	 char infobuff[256];
1836 	 Warn1("refusing connection from %s due to range option",
1837 	       sockaddr_info(&pa->soa, 0,
1838 			     infobuff, sizeof(infobuff)));
1839 	 return -1;
1840       }
1841       Info1("permitting connection from %s due to range option",
1842 	    sockaddr_info(&pa->soa, 0,
1843 			  infobuff, sizeof(infobuff)));
1844    }
1845 #endif /* WITH_IP4 */
1846 
1847 #if WITH_TCP || WITH_UDP
1848    if (xfd->para.socket.ip.dosourceport) {
1849       if (pa == NULL)  { return -1; }
1850 #if WITH_IP4
1851       if (pa->soa.sa_family == AF_INET &&
1852 	  ntohs(((struct sockaddr_in *)pa)->sin_port) != xfd->para.socket.ip.sourceport) {
1853 	 Warn1("refusing connection from %s due to wrong sourceport",
1854 	       sockaddr_info(&pa->soa, 0,
1855 			     infobuff, sizeof(infobuff)));
1856 	 return -1;
1857       }
1858 #endif /* WITH_IP4 */
1859 #if WITH_IP6
1860       if (pa->soa.sa_family == AF_INET6 &&
1861 	  ntohs(((struct sockaddr_in6 *)pa)->sin6_port) != xfd->para.socket.ip.sourceport) {
1862 	 Warn1("refusing connection from %s due to wrong sourceport",
1863 	       sockaddr_info(&pa->soa, 0,
1864 			     infobuff, sizeof(infobuff)));
1865 	 return -1;
1866       }
1867 #endif /* WITH_IP6 */
1868       Info1("permitting connection from %s due to sourceport option",
1869 	    sockaddr_info(&pa->soa, 0,
1870 			  infobuff, sizeof(infobuff)));
1871    } else if (xfd->para.socket.ip.lowport) {
1872       if (pa == NULL)  { return -1; }
1873       if (pa->soa.sa_family == AF_INET &&
1874 	  ntohs(((struct sockaddr_in *)pa)->sin_port) >= IPPORT_RESERVED) {
1875 	 Warn1("refusing connection from %s due to lowport option",
1876 	       sockaddr_info(&pa->soa, 0,
1877 			     infobuff, sizeof(infobuff)));
1878 	 return -1;
1879       }
1880 #if WITH_IP6
1881       else if (pa->soa.sa_family == AF_INET6 &&
1882 	       ntohs(((struct sockaddr_in6 *)pa)->sin6_port) >=
1883 	       IPPORT_RESERVED) {
1884 	 Warn1("refusing connection from %s due to lowport option",
1885 	       sockaddr_info(&pa->soa, 0,
1886 			     infobuff, sizeof(infobuff)));
1887 	 return -1;
1888       }
1889 #endif /* WITH_IP6 */
1890       Info1("permitting connection from %s due to lowport option",
1891 	    sockaddr_info(&pa->soa, 0,
1892 			  infobuff, sizeof(infobuff)));
1893    }
1894 #endif /* WITH_TCP || WITH_UDP */
1895 
1896 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
1897    result = xio_tcpwrap_check(xfd, la, pa);
1898    if (result < 0) {
1899       char infobuff[256];
1900       Warn1("refusing connection from %s due to tcpwrapper option",
1901 	    sockaddr_info(&pa->soa, 0,
1902 			  infobuff, sizeof(infobuff)));
1903       return -1;
1904    } else if (result > 0) {
1905       Info1("permitting connection from %s due to tcpwrapper option",
1906 	    sockaddr_info(&pa->soa, 0,
1907 			  infobuff, sizeof(infobuff)));
1908    }
1909 #endif /* (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
1910 
1911    return 0;	/* permitted */
1912 }
1913 
1914 
1915 #if HAVE_STRUCT_CMSGHDR
1916 /* converts the ancillary message in *cmsg into a form useable for further
1917    processing. knows the specifics of common message types.
1918    returns the number of resulting syntax elements in *num
1919    returns a sequence of \0 terminated type strings in *typbuff
1920    returns a sequence of \0 terminated name strings in *nambuff
1921    returns a sequence of \0 terminated value strings in *valbuff
1922    the respective len parameters specify the available space in the buffers
1923    returns STAT_OK or other STAT_*
1924  */
1925 static int
xiolog_ancillary_socket(struct cmsghdr * cmsg,int * num,char * typbuff,int typlen,char * nambuff,int namlen,char * envbuff,int envlen,char * valbuff,int vallen)1926 xiolog_ancillary_socket(struct cmsghdr *cmsg, int *num,
1927 			char *typbuff, int typlen,
1928 			char *nambuff, int namlen,
1929 			char *envbuff, int envlen,
1930 			char *valbuff, int vallen) {
1931    const char *cmsgtype, *cmsgname, *cmsgenvn;
1932    size_t msglen;
1933    struct timeval *tv;
1934    int rc = STAT_OK;
1935 
1936 #if defined(CMSG_DATA)
1937 
1938    msglen = cmsg->cmsg_len-((char *)CMSG_DATA(cmsg)-(char *)cmsg);
1939    switch (cmsg->cmsg_type) {
1940 #ifdef SO_PASSCRED
1941    case SO_PASSCRED:	/* this is really a UNIX/LOCAL message */
1942       /*! needs implementation */
1943 #endif /* SO_PASSCRED */
1944 #ifdef SO_RIGHTS
1945    case SO_RIGHTS:	/* this is really a UNIX/LOCAL message */
1946       /*! needs implementation */
1947 #endif
1948    default:	/* binary data */
1949       snprintf(typbuff, typlen, "SOCKET.%u", cmsg->cmsg_type);
1950       nambuff[0] = '\0'; strncat(nambuff, "data", namlen-1);
1951       xiodump(CMSG_DATA(cmsg), msglen, valbuff, vallen, 0);
1952       return STAT_OK;
1953 #ifdef SO_TIMESTAMP
1954 #  ifdef SCM_TIMESTAMP
1955    case SCM_TIMESTAMP:
1956 #  else
1957    case SO_TIMESTAMP:
1958 #  endif
1959       tv = (struct timeval *)CMSG_DATA(cmsg);
1960       cmsgtype =
1961 #ifdef SCM_TIMESTAMP
1962 	 "SCM_TIMESTAMP"	/* FreeBSD */
1963 #else
1964 	 "SO_TIMESTAMP"		/* Linux */
1965 #endif
1966 	    ;
1967       cmsgname = "timestamp";
1968       cmsgenvn = "TIMESTAMP";
1969       { time_t t = tv->tv_sec; ctime_r(&t, valbuff); }
1970       snprintf(strchr(valbuff, '\0')-1/*del \n*/, vallen-strlen(valbuff)+1, ", %06ld usecs", (long)tv->tv_usec);
1971       break;
1972 #endif /* defined(SO_TIMESTAMP) */
1973       ;
1974    }
1975    /* when we come here we provide a single parameter
1976       with type in cmsgtype, name in cmsgname,
1977       and value already in valbuff */
1978    *num = 1;
1979    if (strlen(cmsgtype) >= typlen)  rc = STAT_WARNING;
1980    typbuff[0] = '\0'; strncat(typbuff, cmsgtype, typlen-1);
1981    if (strlen(cmsgname) >= namlen)  rc = STAT_WARNING;
1982    nambuff[0] = '\0'; strncat(nambuff, cmsgname, namlen-1);
1983    if (strlen(cmsgenvn) >= envlen)  rc = STAT_WARNING;
1984    envbuff[0] = '\0'; strncat(envbuff, cmsgenvn, envlen-1);
1985    return rc;
1986 
1987 #else /* !defined(CMSG_DATA) */
1988 
1989    return STAT_NORETRY;
1990 
1991 #endif /* !defined(CMSG_DATA) */
1992 }
1993 #endif /* HAVE_STRUCT_CMSGHDR */
1994 
1995 
1996 /* return the name of the interface with given index
1997    or NULL if is fails
1998    The system call requires an arbitrary socket; the calling program may
1999    provide one in parameter ins to avoid creation of a dummy socket. ins must
2000    be <0 if it does not specify a socket fd. */
xiogetifname(int ind,char * val,int ins)2001 char *xiogetifname(int ind, char *val, int ins) {
2002 #if !HAVE_PROTOTYPE_LIB_if_indextoname
2003    int s;
2004    struct ifreq ifr;
2005 
2006    if (ins >= 0) {
2007       s = ins;
2008    } else {
2009       if ((s = Socket(PF_INET, SOCK_DGRAM, IPPROTO_IP)) < 0) {
2010 	 Error1("socket(PF_INET, SOCK_DGRAM, IPPROTO_IP): %s", strerror(errno));
2011 	 return NULL;
2012       }
2013    }
2014 
2015 #if HAVE_STRUCT_IFREQ_IFR_INDEX
2016    ifr.ifr_index = ind;
2017 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
2018    ifr.ifr_ifindex = ind;
2019 #endif
2020 #ifdef SIOCGIFNAME
2021    if(Ioctl(s, SIOCGIFNAME, &ifr) < 0) {
2022 #if HAVE_STRUCT_IFREQ_IFR_INDEX
2023       Info3("ioctl(%d, SIOCGIFNAME, {..., ifr_index=%d, ...}: %s",
2024 	    s, ifr.ifr_index, strerror(errno));
2025 #elif HAVE_STRUCT_IFREQ_IFR_IFINDEX
2026       Info3("ioctl(%d, SIOCGIFNAME, {..., ifr_ifindex=%d, ...}: %s",
2027 	    s, ifr.ifr_ifindex, strerror(errno));
2028 #endif
2029       if (ins < 0)  Close(s);
2030       return NULL;
2031    }
2032 #endif /* SIOCGIFNAME */
2033    if (ins < 0)  Close(s);
2034    strcpy(val, ifr.ifr_name);
2035    return val;
2036 #else /* HAVE_PROTOTYPE_LIB_if_indextoname */
2037    return if_indextoname(ind, val);
2038 #endif /* HAVE_PROTOTYPE_LIB_if_indextoname */
2039 }
2040 
2041 
2042 /* parses a network specification consisting of an address and a mask. */
xioparsenetwork(const char * rangename,int pf,struct xiorange * range)2043 int xioparsenetwork(const char *rangename, int pf, struct xiorange *range) {
2044    size_t addrlen = 0, masklen = 0;
2045    int result;
2046 
2047   switch (pf) {
2048 #if WITH_IP4
2049   case PF_INET:
2050       return xioparsenetwork_ip4(rangename, range);
2051    break;
2052 #endif /* WITH_IP4 */
2053 #if WITH_IP6
2054    case PF_INET6:
2055       return xioparsenetwork_ip6(rangename, range);
2056       break;
2057 #endif /* WITH_IP6 */
2058   case PF_UNSPEC:
2059     {
2060      char *addrname;
2061      const char *maskname;
2062      if ((maskname = strchr(rangename, ':')) == NULL) {
2063 	Error1("syntax error in range \"%s\": use <addr>:<mask>", rangename);
2064 	return STAT_NORETRY;
2065      }
2066      ++maskname;	/* skip ':' */
2067      if ((addrname = Malloc(maskname-rangename)) == NULL) {
2068 	return STAT_NORETRY;
2069      }
2070      strncpy(addrname, rangename, maskname-rangename-1);	/* ok */
2071      addrname[maskname-rangename-1] = '\0';
2072      result =
2073 	dalan(addrname, (uint8_t *)&range->netaddr.soa.sa_data, &addrlen,
2074 	      sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data)
2075 	      /* data length */, 'i');
2076      if (result < 0) {
2077 	Error1("data too long: \"%s\"", addrname);
2078 	free(addrname); return STAT_NORETRY;
2079      } else if (result > 0) {
2080 	Error1("syntax error in \"%s\"", addrname);
2081 	free(addrname); return STAT_NORETRY;
2082      }
2083      free(addrname);
2084      result =
2085 	dalan(maskname, (uint8_t *)&range->netmask.soa.sa_data, &masklen,
2086 	      sizeof(range->netaddr)-(size_t)(&((struct sockaddr *)0)->sa_data)
2087 	      /* data length */, 'i');
2088      if (result < 0) {
2089 	Error1("data too long: \"%s\"", maskname);
2090 	return STAT_NORETRY;
2091      } else if (result > 0) {
2092 	Error1("syntax error in \"%s\"", maskname);
2093 	return STAT_NORETRY;
2094      }
2095 	 if (addrlen != masklen) {
2096 	    Error2("network address is "F_Zu" bytes long, mask is "F_Zu" bytes long",
2097 		   addrlen, masklen);
2098 	    /* recover by padding the shorter component with 0 */
2099 	    memset((char *)&range->netaddr.soa.sa_data+addrlen, 0,
2100 		   MAX(0, addrlen-masklen));
2101 	    memset((char *)&range->netmask.soa.sa_data+masklen, 0,
2102 		   MAX(0, masklen-addrlen));
2103 	 }
2104     }
2105     break;
2106   default:
2107      Error1("range option not supported with address family %d", pf);
2108      return STAT_NORETRY;
2109   }
2110   return STAT_OK;
2111 }
2112 
2113 
2114 /* parses a string of form address/bits or address:mask, and fills the fields
2115    of the range union. The addr component is masked with mask. */
xioparserange(const char * rangename,int pf,struct xiorange * range)2116 int xioparserange(const char *rangename, int pf, struct xiorange *range) {
2117    int i;
2118    if (xioparsenetwork(rangename, pf, range) < 0) {
2119       return -1;
2120    }
2121    /* we have parsed the address and mask; now we make sure that the stored
2122       address has 0 where mask is 0, to simplify comparisions */
2123    switch (pf) {
2124 #if WITH_IP4
2125    case PF_INET:
2126       range->netaddr.ip4.sin_addr.s_addr &= range->netmask.ip4.sin_addr.s_addr;
2127       break;
2128 #endif /* WITH_IP4 */
2129 #if WITH_IP6
2130    case PF_INET6:
2131       return xiorange_ip6andmask(range);
2132       break;
2133 #endif /* WITH_IP6 */
2134    case PF_UNSPEC:
2135       for (i = 0; i < sizeof(range->netaddr); ++i) {
2136 	 ((char *)&range->netaddr)[i] &= ((char *)&range->netmask)[i];
2137       }
2138       break;
2139    default:
2140       Error1("range option not supported with address family %d", pf);
2141       return STAT_NORETRY;
2142    }
2143    return 0;
2144 }
2145 
2146 
2147 /* set environment variables describing (part of) a socket address, e.g.
2148    SOCAT_SOCKADDR. lr (local/remote) specifies a string like  "SOCK" or "PEER".
2149    proto should correspond to the third parameter of socket(2) and is used to
2150    determine the presence of port information. */
xiosetsockaddrenv(const char * lr,union sockaddr_union * sau,socklen_t salen,int proto)2151 int xiosetsockaddrenv(const char *lr,
2152 		      union sockaddr_union *sau, socklen_t salen,
2153 		      int proto) {
2154 #  define XIOSOCKADDRENVLEN 256
2155    char namebuff[XIOSOCKADDRENVLEN];
2156    char valuebuff[XIOSOCKADDRENVLEN];
2157    int idx = 0, result;
2158 
2159    strcpy(namebuff, lr);
2160    switch (sau->soa.sa_family) {
2161 #if WITH_UNIX
2162    case PF_UNIX:
2163       result =
2164 	 xiosetsockaddrenv_unix(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
2165 				valuebuff, XIOSOCKADDRENVLEN,
2166 				&sau->un, salen, proto);
2167       xiosetenv(namebuff, valuebuff, 1, NULL);
2168       break;
2169 #endif /* WITH_UNIX */
2170 #if WITH_IP4
2171    case PF_INET:
2172       do {
2173 	 result =
2174 	    xiosetsockaddrenv_ip4(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
2175 				  valuebuff, XIOSOCKADDRENVLEN,
2176 				  &sau->ip4, proto);
2177 	 xiosetenv(namebuff, valuebuff, 1, NULL);
2178 	 namebuff[strlen(lr)] = '\0';  ++idx;
2179       } while (result > 0);
2180       break;
2181 #endif /* WITH_IP4 */
2182 #if WITH_IP6
2183    case PF_INET6:
2184       strcpy(namebuff, lr);
2185       do {
2186 	 result =
2187 	    xiosetsockaddrenv_ip6(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
2188 				  valuebuff, XIOSOCKADDRENVLEN,
2189 				  &sau->ip6, proto);
2190 	 xiosetenv(namebuff, valuebuff, 1, NULL);
2191 	 namebuff[strlen(lr)] = '\0';  ++idx;
2192       } while (result > 0);
2193       break;
2194 #endif /* WITH_IP6 */
2195 #if LATER
2196    case PF_PACKET:
2197       result = xiosetsockaddrenv_packet(lr, (void *)sau, proto); break;
2198 #endif
2199    default:
2200       result = -1;
2201       break;
2202    }
2203    return result;
2204 #  undef XIOSOCKADDRENVLEN
2205 }
2206 
2207 #endif /* _WITH_SOCKET */
2208 
2209 /* these do sockets internally */
2210 
2211 /* retrieves options so-type and so-prototype from opts, calls socket, and
2212    ev. generates an appropriate error message.
2213    returns 0 on success or -1 if an error occurred. */
2214 int
xiosocket(struct opt * opts,int pf,int socktype,int proto,int msglevel)2215 xiosocket(struct opt *opts, int pf, int socktype, int proto, int msglevel) {
2216    int result;
2217 
2218    retropt_int(opts, OPT_SO_TYPE, &socktype);
2219    retropt_int(opts, OPT_SO_PROTOTYPE, &proto);
2220    result = Socket(pf, socktype, proto);
2221    if (result < 0) {
2222       Msg4(msglevel, "socket(%d, %d, %d): %s",
2223 	     pf, socktype, proto, strerror(errno));
2224       return -1;
2225    }
2226    return result;
2227 }
2228 
2229 /* retrieves options so-type and so-prototype from opts, calls socketpair, and
2230    ev. generates an appropriate error message.
2231    returns 0 on success or -1 if an error occurred. */
2232 int
xiosocketpair(struct opt * opts,int pf,int socktype,int proto,int sv[2])2233 xiosocketpair(struct opt *opts, int pf, int socktype, int proto, int sv[2]) {
2234    int result;
2235 
2236    retropt_int(opts, OPT_SO_TYPE, &socktype);
2237    retropt_int(opts, OPT_SO_PROTOTYPE, &proto);
2238    result = Socketpair(pf, socktype, proto, sv);
2239    if (result < 0) {
2240       Error5("socketpair(%d, %d, %d, %p): %s",
2241 	     pf, socktype, proto, sv, strerror(errno));
2242       return -1;
2243    }
2244    return result;
2245 }
2246