version 1.7.3.0
[socat.git] / xio-rawip.c
blob0cbed31ec2935e4d825525d4e240a31acba0844f
1 /* source: xio-rawip.c */
2 /* Copyright Gerhard Rieger 2001-2008 */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for opening addresses of raw IP type */
7 #include "xiosysincludes.h"
9 #if (WITH_IP4 || WITH_IP6) && WITH_RAWIP
11 #include "xioopen.h"
12 #include "xio-socket.h"
13 #include "xio-ip.h"
14 #include "xio-ip6.h"
15 #include "xio-tcpwrap.h"
17 #include "xio-rawip.h"
20 static
21 int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts,
22 int xioflags, xiofile_t *fd, unsigned groups, int pf,
23 int dummy2, int dummy3);
24 static
25 int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts,
26 int xioflags, xiofile_t *fd, unsigned groups, int pf,
27 int dummy2, int dummy3);
28 static
29 int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
30 int xioflags, xiofile_t *xfd, unsigned groups,
31 int pf, int socktype, int dummy3);
32 static
33 int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
34 int xioflags, xiofile_t *xfd, unsigned groups,
35 int pf, int socktype, int ipproto);
37 static
38 int _xioopen_rawip_sendto(const char *hostname, const char *protname,
39 struct opt *opts, int xioflags,
40 xiofile_t *xxfd, unsigned groups, int *pf);
42 const struct addrdesc addr_rawip_sendto = { "ip-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
43 const struct addrdesc addr_rawip_datagram= { "ip-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
44 const struct addrdesc addr_rawip_recvfrom= { "ip-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
45 const struct addrdesc addr_rawip_recv = { "ip-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
47 #if WITH_IP4
48 const struct addrdesc addr_rawip4_sendto = { "ip4-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
49 const struct addrdesc addr_rawip4_datagram= { "ip4-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
50 const struct addrdesc addr_rawip4_recvfrom= { "ip4-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_CHILD|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
51 const struct addrdesc addr_rawip4_recv = { "ip4-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
52 #endif
54 #if WITH_IP6
55 const struct addrdesc addr_rawip6_sendto = { "ip6-sendto", 3, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
56 const struct addrdesc addr_rawip6_datagram= { "ip6-datagram", 3, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
57 const struct addrdesc addr_rawip6_recvfrom= { "ip6-recvfrom", 3, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
58 const struct addrdesc addr_rawip6_recv = { "ip6-recv", 1, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
59 #endif
62 /* we expect the form: host:protocol */
63 /* struct sockaddr_in sa;*/
64 /* socklen_t salen;*/
65 static
66 int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts,
67 int xioflags, xiofile_t *xxfd, unsigned groups,
68 int pf, int dummy2, int dummy3) {
69 int result;
71 if (argc != 3) {
72 Error2("%s: wrong number of parameters (%d instead of 2)",
73 argv[0], argc-1);
74 return STAT_NORETRY;
76 if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
77 groups, &pf)) != STAT_OK) {
78 return result;
80 _xio_openlate(&xxfd->stream, opts);
81 return STAT_OK;
85 applies and consumes the following options:
86 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
87 OFUNC_OFFSET
88 OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER,
89 OPT_GROUP, OPT_CLOEXEC
91 static
92 int _xioopen_rawip_sendto(const char *hostname, const char *protname,
93 struct opt *opts, int xioflags, xiofile_t *xxfd,
94 unsigned groups, int *pf) {
95 char *garbage;
96 xiosingle_t *xfd = &xxfd->stream;
97 union sockaddr_union us;
98 socklen_t uslen;
99 int feats = 1; /* option bind supports only address, not port */
100 int socktype = SOCK_RAW;
101 int ipproto;
102 bool needbind = false;
103 int result;
105 if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
106 Error3("xioopen_rawip_sendto(\"%s:%s\",,): protocol number exceeds 255 (%u)",
107 hostname, protname, ipproto);
108 return STAT_NORETRY;
109 } else if (*garbage) {
110 Warn2("xioopen_rawip_sendto(\"%s:%s\",,): trailing garbage in protocol specification",
111 hostname, protname);
112 /*return STAT_NORETRY;*/
115 xfd->howtoend = END_SHUTDOWN;
116 retropt_int(opts, OPT_PROTOCOL_FAMILY, pf);
118 /* ...res_opts[] */
119 if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1;
120 applyopts(-1, opts, PH_INIT);
122 xfd->salen = sizeof(xfd->peersa);
123 if ((result =
124 xiogetaddrinfo(hostname, NULL, *pf, socktype, ipproto,
125 &xfd->peersa, &xfd->salen,
126 xfd->para.socket.ip.res_opts[0],
127 xfd->para.socket.ip.res_opts[1]))
128 != STAT_OK) {
129 return result;
131 if (*pf == PF_UNSPEC) {
132 *pf = xfd->peersa.soa.sa_family;
135 uslen = socket_init(*pf, &us);
137 xfd->dtype = XIODATA_RECVFROM_SKIPIP;
139 if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats,
140 xfd->para.socket.ip.res_opts[0],
141 xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) {
142 needbind = true;
144 return
145 _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
146 opts, xioflags, xfd, groups, *pf, socktype, ipproto);
150 /* we expect the form: address:protocol */
151 static
152 int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts,
153 int xioflags, xiofile_t *xxfd, unsigned groups,
154 int pf, int dummy2, int dummy3) {
155 xiosingle_t *xfd = &xxfd->stream;
156 char *rangename;
157 int result;
159 if (argc != 3) {
160 Error2("%s: wrong number of parameters (%d instead of 2)",
161 argv[0], argc-1);
162 return STAT_NORETRY;
164 if ((result =
165 _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
166 groups, &pf)) != STAT_OK) {
167 return result;
170 xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
171 if (pf == PF_INET) {
172 xfd->dtype |= XIOREAD_RECV_SKIPIP;
175 xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family;
177 /* which reply packets will be accepted - determine by range option */
178 if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
179 if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) {
180 free(rangename);
181 return STAT_NORETRY;
183 xfd->para.socket.dorange = true;
184 xfd->dtype |= XIOREAD_RECV_CHECKRANGE;
185 free(rangename);
188 #if WITH_LIBWRAP
189 xio_retropt_tcpwrap(xfd, opts);
190 #endif /* WITH_LIBWRAP */
192 _xio_openlate(xfd, opts);
193 return STAT_OK;
197 static
198 int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts,
199 int xioflags, xiofile_t *xfd, unsigned groups,
200 int pf, int socktype, int dummy3) {
201 const char *protname = argv[1];
202 char *garbage;
203 union sockaddr_union us;
204 socklen_t uslen = sizeof(us);
205 int ipproto;
206 bool needbind = false;
207 int result;
209 if (argc != 2) {
210 Error2("%s: wrong number of parameters (%d instead of 1)",
211 argv[0], argc-1);
212 return STAT_NORETRY;
215 if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
216 Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)",
217 protname, ipproto);
218 return STAT_NORETRY;
219 } else if (*garbage) {
220 Warn1("xioopen_rawip_recvfrom(\"%s\",,): trailing garbage in protocol specification",
221 protname);
222 /*return STAT_NORETRY;*/
224 xfd->stream.howtoend = END_NONE;
226 retropt_socket_pf(opts, &pf);
227 if (pf == PF_UNSPEC) {
228 #if WITH_IP4 && WITH_IP6
229 pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
230 #elif WITH_IP6
231 pf = PF_INET6;
232 #else
233 pf = PF_INET;
234 #endif
237 if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1,
238 xfd->stream.para.socket.ip.res_opts[0],
239 xfd->stream.para.socket.ip.res_opts[1]) != STAT_NOACTION) {
240 needbind = true;
243 xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE;
244 if ((result =
245 _xioopen_dgram_recvfrom(&xfd->stream, xioflags, needbind?&us.soa:NULL,
246 uslen, opts, pf, socktype, ipproto, E_ERROR))
247 != STAT_OK) {
248 return result;
250 _xio_openlate(&xfd->stream, opts);
251 return STAT_OK;
255 static
256 int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts,
257 int xioflags, xiofile_t *xfd, unsigned groups,
258 int pf, int socktype, int dummy3) {
259 const char *protname = argv[1];
260 char *garbage;
261 bool needbind = false;
262 union sockaddr_union us;
263 socklen_t uslen = sizeof(us);
264 int ipproto;
265 int result;
267 if (argc != 2) {
268 Error2("%s: wrong number of parameters (%d instead of 1)",
269 argv[0], argc-1);
270 return STAT_NORETRY;
273 if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
274 Error2("xioopen_rawip_recv(\"%s\",,): protocol number exceeds 255 (%u)",
275 protname, ipproto);
276 return STAT_NORETRY;
277 } else if (*garbage) {
278 Warn1("xioopen_rawip_recv(\"%s\",,): trailing garbage in protocol specification",
279 protname);
280 /*return STAT_NORETRY;*/
283 retropt_socket_pf(opts, &pf);
284 if (pf == PF_UNSPEC) {
285 #if WITH_IP4 && WITH_IP6
286 pf = xioopts.default_ip=='6'?PF_INET6:PF_INET;
287 #elif WITH_IP6
288 pf = PF_INET6;
289 #else
290 pf = PF_INET;
291 #endif
294 if (retropt_bind(opts, pf, socktype, ipproto,
295 &/*us.soa*/xfd->stream.para.socket.la.soa, &uslen, 1,
296 xfd->stream.para.socket.ip.res_opts[0],
297 xfd->stream.para.socket.ip.res_opts[1]) ==
298 STAT_OK) {
299 needbind = true;
300 } else {
301 /* pf is required during xioread checks */
302 xfd->stream.para.socket.la.soa.sa_family = pf;
305 xfd->stream.dtype = XIODATA_RECV_SKIPIP;
306 result =
307 _xioopen_dgram_recv(&xfd->stream, xioflags,
308 needbind?&/*us.soa*/xfd->stream.para.socket.la.soa:NULL,
309 uslen,
310 opts, pf, socktype, ipproto, E_ERROR);
311 _xio_openlate(&xfd->stream, opts);
312 return result;
315 #endif /* (WITH_IP4 || WITH_IP6) && WITH_RAWIP */