Version 1.8.0.0
[socat.git] / xio-rawip.c
blobe4d38125d0223cd0be923e244be419a29f83f580
1 /* source: xio-rawip.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
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 int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
21 static int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc);
22 static int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
23 static int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc);
25 static
26 int _xioopen_rawip_sendto(const char *hostname, const char *protname,
27 struct opt *opts, int xioflags,
28 xiofile_t *xxfd, groups_t groups, int *pf);
30 const struct addrdesc xioaddr_rawip_sendto = { "IP-SENDTO", 1+XIO_RDWR, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
31 const struct addrdesc xioaddr_rawip_datagram= { "IP-DATAGRAM", 1+XIO_RDWR, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, 0, 0 HELP(":<host>:<protocol>") };
32 const struct addrdesc xioaddr_rawip_recvfrom= { "IP-RECVFROM", 1+XIO_RDWR, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
33 const struct addrdesc xioaddr_rawip_recv = { "IP-RECV", 1+XIO_RDONLY, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_SOCK_IP6|GROUP_RANGE, PF_UNSPEC, SOCK_RAW, 0 HELP(":<protocol>") };
35 #if WITH_IP4
36 const struct addrdesc xioaddr_rawip4_sendto = { "IP4-SENDTO", 1+XIO_RDWR, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
37 const struct addrdesc xioaddr_rawip4_datagram= { "IP4-DATAGRAM", 1+XIO_RDWR, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, 0, 0 HELP(":<host>:<protocol>") };
38 const struct addrdesc xioaddr_rawip4_recvfrom= { "IP4-RECVFROM", 1+XIO_RDWR, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_CHILD|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
39 const struct addrdesc xioaddr_rawip4_recv = { "IP4-RECV", 1+XIO_RDONLY, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP4|GROUP_RANGE, PF_INET, SOCK_RAW, 0 HELP(":<protocol>") };
40 #endif
42 #if WITH_IP6
43 const struct addrdesc xioaddr_rawip6_sendto = { "IP6-SENDTO", 1+XIO_RDWR, xioopen_rawip_sendto, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
44 const struct addrdesc xioaddr_rawip6_datagram= { "IP6-DATAGRAM", 1+XIO_RDWR, xioopen_rawip_datagram, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, 0, 0 HELP(":<host>:<protocol>") };
45 const struct addrdesc xioaddr_rawip6_recvfrom= { "IP6-RECVFROM", 1+XIO_RDWR, xioopen_rawip_recvfrom, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_CHILD|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
46 const struct addrdesc xioaddr_rawip6_recv = { "IP6-RECV", 1+XIO_RDONLY, xioopen_rawip_recv, GROUP_FD|GROUP_SOCKET|GROUP_SOCK_IP6|GROUP_RANGE, PF_INET6, SOCK_RAW, 0 HELP(":<protocol>") };
47 #endif
50 /* we expect the form: host:protocol */
51 /* struct sockaddr_in sa;*/
52 /* socklen_t salen;*/
53 static int xioopen_rawip_sendto(
54 int argc,
55 const char *argv[],
56 struct opt *opts,
57 int xioflags,
58 xiofile_t *xxfd,
59 const struct addrdesc *addrdesc)
61 int pf = addrdesc->arg1;
62 int result;
64 if (argc != 3) {
65 xio_syntax(argv[0], 2, argc-1, addrdesc->syntax);
66 return STAT_NORETRY;
69 xioinit_ip(&pf, xioparms.preferred_ip);
70 if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
71 addrdesc->groups, &pf)) != STAT_OK) {
72 return result;
74 _xio_openlate(&xxfd->stream, opts);
75 return STAT_OK;
79 applies and consumes the following options:
80 PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE
81 OFUNC_OFFSET
82 OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER,
83 OPT_GROUP, OPT_CLOEXEC
85 static
86 int _xioopen_rawip_sendto(const char *hostname, const char *protname,
87 struct opt *opts, int xioflags, xiofile_t *xxfd,
88 groups_t groups, int *pf) {
89 char *garbage;
90 xiosingle_t *sfd = &xxfd->stream;
91 union sockaddr_union us;
92 socklen_t uslen;
93 int feats = 1; /* option bind supports only address, not port */
94 int socktype = SOCK_RAW;
95 int ipproto;
96 bool needbind = false;
97 int result;
99 if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
100 Error3("xioopen_rawip_sendto(\"%s:%s\",,): protocol number exceeds 255 (%u)",
101 hostname, protname, ipproto);
102 return STAT_NORETRY;
103 } else if (*garbage) {
104 Warn2("xioopen_rawip_sendto(\"%s:%s\",,): trailing garbage in protocol specification",
105 hostname, protname);
106 /*return STAT_NORETRY;*/
109 if (sfd->howtoend == END_UNSPEC)
110 sfd->howtoend = END_SHUTDOWN;
111 retropt_int(opts, OPT_PROTOCOL_FAMILY, pf);
113 if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
114 applyopts(sfd, -1, opts, PH_INIT);
116 sfd->salen = sizeof(sfd->peersa);
117 if ((result =
118 xioresolve(hostname, NULL, *pf, socktype, ipproto,
119 &sfd->peersa, &sfd->salen,
120 sfd->para.socket.ip.ai_flags))
121 != STAT_OK) {
122 return result;
124 if (*pf == PF_UNSPEC) {
125 *pf = sfd->peersa.soa.sa_family;
128 uslen = socket_init(*pf, &us);
130 sfd->dtype = XIODATA_RECVFROM_SKIPIP;
132 if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats,
133 sfd->para.socket.ip.ai_flags)
134 != STAT_NOACTION) {
135 needbind = true;
137 return
138 _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
139 opts, xioflags, sfd, groups, *pf, socktype, ipproto, 0);
143 /* we expect the form: address:protocol */
144 static int xioopen_rawip_datagram(
145 int argc,
146 const char *argv[],
147 struct opt *opts,
148 int xioflags,
149 xiofile_t *xxfd,
150 const struct addrdesc *addrdesc)
152 xiosingle_t *sfd = &xxfd->stream;
153 int pf = addrdesc->arg1;
154 char *rangename;
155 int result;
157 if (argc != 3) {
158 xio_syntax(argv[0], 2, argc-1, addrdesc->syntax);
159 return STAT_NORETRY;
162 xioinit_ip(&pf, xioparms.preferred_ip);
163 if ((result =
164 _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd,
165 addrdesc->groups, &pf)) != STAT_OK) {
166 return result;
169 sfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO;
170 if (pf == PF_INET) {
171 sfd->dtype |= XIOREAD_RECV_SKIPIP;
174 sfd->para.socket.la.soa.sa_family = sfd->peersa.soa.sa_family;
176 /* which reply packets will be accepted - determine by range option */
177 if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
178 if (xioparserange(rangename, pf, &sfd->para.socket.range,
179 sfd->para.socket.ip.ai_flags)
180 < 0) {
181 free(rangename);
182 return STAT_NORETRY;
184 sfd->para.socket.dorange = true;
185 sfd->dtype |= XIOREAD_RECV_CHECKRANGE;
186 free(rangename);
189 #if WITH_LIBWRAP
190 xio_retropt_tcpwrap(sfd, opts);
191 #endif /* WITH_LIBWRAP */
193 _xio_openlate(sfd, opts);
194 return STAT_OK;
198 static int xioopen_rawip_recvfrom(
199 int argc,
200 const char *argv[],
201 struct opt *opts,
202 int xioflags,
203 xiofile_t *xfd,
204 const struct addrdesc *addrdesc)
206 struct single *sfd = &xfd->stream;
207 const char *protname = argv[1];
208 int pf = addrdesc->arg1;
209 int socktype = addrdesc->arg2;
210 char *garbage;
211 union sockaddr_union us;
212 socklen_t uslen = sizeof(us);
213 int ipproto;
214 bool needbind = false;
215 int result;
217 if (argc != 2) {
218 xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
219 return STAT_NORETRY;
222 xioinit_ip(&pf, xioparms.default_ip);
223 if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
224 Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)",
225 protname, ipproto);
226 return STAT_NORETRY;
227 } else if (*garbage) {
228 Warn1("xioopen_rawip_recvfrom(\"%s\",,): trailing garbage in protocol specification",
229 protname);
230 /*return STAT_NORETRY;*/
232 if (sfd->howtoend == END_UNSPEC)
233 sfd->howtoend = END_NONE;
235 retropt_socket_pf(opts, &pf);
236 if (pf == PF_UNSPEC) {
237 #if WITH_IP4 && WITH_IP6
238 switch (xioparms.default_ip) {
239 case '4': pf = PF_INET; break;
240 case '6': pf = PF_INET6; break;
241 default: break; /* includes \0 */
243 #elif WITH_IP6
244 pf = PF_INET6;
245 #else
246 pf = PF_INET;
247 #endif
250 if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1,
251 sfd->para.socket.ip.ai_flags)
252 != STAT_NOACTION) {
253 needbind = true;
256 sfd->dtype = XIODATA_RECVFROM_SKIPIP_ONE;
257 if ((result =
258 _xioopen_dgram_recvfrom(sfd, xioflags, needbind?&us.soa:NULL,
259 uslen, opts, pf, socktype, ipproto, E_ERROR))
260 != STAT_OK) {
261 return result;
263 _xio_openlate(sfd, opts);
264 return STAT_OK;
268 static int xioopen_rawip_recv(
269 int argc,
270 const char *argv[],
271 struct opt *opts,
272 int xioflags,
273 xiofile_t *xfd,
274 const struct addrdesc *addrdesc)
276 const char *protname = argv[1];
277 int pf = addrdesc->arg1;
278 int socktype = addrdesc->arg2;
279 char *garbage;
280 bool needbind = false;
281 union sockaddr_union us;
282 socklen_t uslen = sizeof(us);
283 int ipproto;
284 int result;
286 if (argc != 2) {
287 xio_syntax(argv[0], 1, argc-1, addrdesc->syntax);
288 return STAT_NORETRY;
291 xioinit_ip(&pf, xioparms.default_ip);
292 if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) {
293 Error2("xioopen_rawip_recv(\"%s\",,): protocol number exceeds 255 (%u)",
294 protname, ipproto);
295 return STAT_NORETRY;
296 } else if (*garbage) {
297 Warn1("xioopen_rawip_recv(\"%s\",,): trailing garbage in protocol specification",
298 protname);
299 /*return STAT_NORETRY;*/
302 retropt_socket_pf(opts, &pf);
303 if (pf == PF_UNSPEC) {
304 #if WITH_IP4 && WITH_IP6
305 pf = xioparms.default_ip=='6'?PF_INET6:PF_INET;
306 #elif WITH_IP6
307 pf = PF_INET6;
308 #else
309 pf = PF_INET;
310 #endif
313 if (retropt_bind(opts, pf, socktype, ipproto,
314 &/*us.soa*/xfd->stream.para.socket.la.soa, &uslen, 1,
315 xfd->stream.para.socket.ip.ai_flags)
316 == STAT_OK) {
317 needbind = true;
318 } else {
319 /* pf is required during xioread checks */
320 xfd->stream.para.socket.la.soa.sa_family = pf;
323 xfd->stream.dtype = XIODATA_RECV_SKIPIP;
324 result =
325 _xioopen_dgram_recv(&xfd->stream, xioflags,
326 needbind?&/*us.soa*/xfd->stream.para.socket.la.soa:NULL,
327 uslen,
328 opts, pf, socktype, ipproto, E_ERROR);
329 _xio_openlate(&xfd->stream, opts);
330 return result;
333 #endif /* (WITH_IP4 || WITH_IP6) && WITH_RAWIP */