| /* source: xio-rawip.c */ | |
| /* Copyright Gerhard Rieger and contributors (see file CHANGES) */ | |
| /* Published under the GNU General Public License V.2, see file COPYING */ | |
| /* this file contains the source for opening addresses of raw IP type */ | |
| #include "xiosysincludes.h" | |
| #if (WITH_IP4 || WITH_IP6) && WITH_RAWIP | |
| #include "xioopen.h" | |
| #include "xio-socket.h" | |
| #include "xio-ip.h" | |
| #include "xio-ip6.h" | |
| #include "xio-tcpwrap.h" | |
| #include "xio-rawip.h" | |
| static | |
| int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts, | |
| int xioflags, xiofile_t *fd, unsigned groups, int pf, | |
| int dummy2, int dummy3); | |
| static | |
| int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts, | |
| int xioflags, xiofile_t *fd, unsigned groups, int pf, | |
| int dummy2, int dummy3); | |
| static | |
| int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, | |
| int xioflags, xiofile_t *xfd, unsigned groups, | |
| int pf, int socktype, int dummy3); | |
| static | |
| int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, | |
| int xioflags, xiofile_t *xfd, unsigned groups, | |
| int pf, int socktype, int ipproto); | |
| static | |
| int _xioopen_rawip_sendto(const char *hostname, const char *protname, | |
| struct opt *opts, int xioflags, | |
| xiofile_t *xxfd, unsigned groups, int *pf); | |
| 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>") }; | |
| 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>") }; | |
| 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>") }; | |
| 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>") }; | |
| #if WITH_IP4 | |
| 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>") }; | |
| 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>") }; | |
| 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>") }; | |
| 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>") }; | |
| #endif | |
| #if WITH_IP6 | |
| 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>") }; | |
| 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>") }; | |
| 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>") }; | |
| 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>") }; | |
| #endif | |
| /* we expect the form: host:protocol */ | |
| /* struct sockaddr_in sa;*/ | |
| /* socklen_t salen;*/ | |
| static | |
| int xioopen_rawip_sendto(int argc, const char *argv[], struct opt *opts, | |
| int xioflags, xiofile_t *xxfd, unsigned groups, | |
| int pf, int dummy2, int dummy3) { | |
| int result; | |
| if (argc != 3) { | |
| Error2("%s: wrong number of parameters (%d instead of 2)", | |
| argv[0], argc-1); | |
| return STAT_NORETRY; | |
| } | |
| if ((result = _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, | |
| groups, &pf)) != STAT_OK) { | |
| return result; | |
| } | |
| _xio_openlate(&xxfd->stream, opts); | |
| return STAT_OK; | |
| } | |
| /* | |
| applies and consumes the following options: | |
| PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECTED, PH_LATE | |
| OFUNC_OFFSET | |
| OPT_PROTOCOL_FAMILY, OPT_BIND, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, | |
| OPT_GROUP, OPT_CLOEXEC | |
| */ | |
| static | |
| int _xioopen_rawip_sendto(const char *hostname, const char *protname, | |
| struct opt *opts, int xioflags, xiofile_t *xxfd, | |
| unsigned groups, int *pf) { | |
| char *garbage; | |
| xiosingle_t *xfd = &xxfd->stream; | |
| union sockaddr_union us; | |
| socklen_t uslen; | |
| int feats = 1; /* option bind supports only address, not port */ | |
| int socktype = SOCK_RAW; | |
| int ipproto; | |
| bool needbind = false; | |
| int result; | |
| if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { | |
| Error3("xioopen_rawip_sendto(\"%s:%s\",,): protocol number exceeds 255 (%u)", | |
| hostname, protname, ipproto); | |
| return STAT_NORETRY; | |
| } else if (*garbage) { | |
| Warn2("xioopen_rawip_sendto(\"%s:%s\",,): trailing garbage in protocol specification", | |
| hostname, protname); | |
| /*return STAT_NORETRY;*/ | |
| } | |
| xfd->howtoend = END_SHUTDOWN; | |
| retropt_int(opts, OPT_PROTOCOL_FAMILY, pf); | |
| /* ...res_opts[] */ | |
| if (applyopts_single(xfd, opts, PH_INIT) < 0) return -1; | |
| applyopts(-1, opts, PH_INIT); | |
| xfd->salen = sizeof(xfd->peersa); | |
| if ((result = | |
| xiogetaddrinfo(hostname, NULL, *pf, socktype, ipproto, | |
| &xfd->peersa, &xfd->salen, | |
| xfd->para.socket.ip.res_opts[0], | |
| xfd->para.socket.ip.res_opts[1])) | |
| != STAT_OK) { | |
| return result; | |
| } | |
| if (*pf == PF_UNSPEC) { | |
| *pf = xfd->peersa.soa.sa_family; | |
| } | |
| uslen = socket_init(*pf, &us); | |
| xfd->dtype = XIODATA_RECVFROM_SKIPIP; | |
| if (retropt_bind(opts, *pf, socktype, ipproto, &us.soa, &uslen, feats, | |
| xfd->para.socket.ip.res_opts[0], | |
| xfd->para.socket.ip.res_opts[1]) != STAT_NOACTION) { | |
| needbind = true; | |
| } | |
| return | |
| _xioopen_dgram_sendto(needbind?&us:NULL, uslen, | |
| opts, xioflags, xfd, groups, *pf, socktype, ipproto, 0); | |
| } | |
| /* we expect the form: address:protocol */ | |
| static | |
| int xioopen_rawip_datagram(int argc, const char *argv[], struct opt *opts, | |
| int xioflags, xiofile_t *xxfd, unsigned groups, | |
| int pf, int dummy2, int dummy3) { | |
| xiosingle_t *xfd = &xxfd->stream; | |
| char *rangename; | |
| int result; | |
| if (argc != 3) { | |
| Error2("%s: wrong number of parameters (%d instead of 2)", | |
| argv[0], argc-1); | |
| return STAT_NORETRY; | |
| } | |
| if ((result = | |
| _xioopen_rawip_sendto(argv[1], argv[2], opts, xioflags, xxfd, | |
| groups, &pf)) != STAT_OK) { | |
| return result; | |
| } | |
| xfd->dtype = XIOREAD_RECV|XIOWRITE_SENDTO; | |
| if (pf == PF_INET) { | |
| xfd->dtype |= XIOREAD_RECV_SKIPIP; | |
| } | |
| xfd->para.socket.la.soa.sa_family = xfd->peersa.soa.sa_family; | |
| /* which reply packets will be accepted - determine by range option */ | |
| if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) { | |
| if (xioparserange(rangename, pf, &xfd->para.socket.range) < 0) { | |
| free(rangename); | |
| return STAT_NORETRY; | |
| } | |
| xfd->para.socket.dorange = true; | |
| xfd->dtype |= XIOREAD_RECV_CHECKRANGE; | |
| free(rangename); | |
| } | |
| #if WITH_LIBWRAP | |
| xio_retropt_tcpwrap(xfd, opts); | |
| #endif /* WITH_LIBWRAP */ | |
| _xio_openlate(xfd, opts); | |
| return STAT_OK; | |
| } | |
| static | |
| int xioopen_rawip_recvfrom(int argc, const char *argv[], struct opt *opts, | |
| int xioflags, xiofile_t *xfd, unsigned groups, | |
| int pf, int socktype, int dummy3) { | |
| const char *protname = argv[1]; | |
| char *garbage; | |
| union sockaddr_union us; | |
| socklen_t uslen = sizeof(us); | |
| int ipproto; | |
| bool needbind = false; | |
| int result; | |
| if (argc != 2) { | |
| Error2("%s: wrong number of parameters (%d instead of 1)", | |
| argv[0], argc-1); | |
| return STAT_NORETRY; | |
| } | |
| if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { | |
| Error2("xioopen_rawip_recvfrom(\"%s\",,): protocol number exceeds 255 (%u)", | |
| protname, ipproto); | |
| return STAT_NORETRY; | |
| } else if (*garbage) { | |
| Warn1("xioopen_rawip_recvfrom(\"%s\",,): trailing garbage in protocol specification", | |
| protname); | |
| /*return STAT_NORETRY;*/ | |
| } | |
| xfd->stream.howtoend = END_NONE; | |
| retropt_socket_pf(opts, &pf); | |
| if (pf == PF_UNSPEC) { | |
| #if WITH_IP4 && WITH_IP6 | |
| pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; | |
| #elif WITH_IP6 | |
| pf = PF_INET6; | |
| #else | |
| pf = PF_INET; | |
| #endif | |
| } | |
| if (retropt_bind(opts, pf, socktype, ipproto, &us.soa, &uslen, 1, | |
| xfd->stream.para.socket.ip.res_opts[0], | |
| xfd->stream.para.socket.ip.res_opts[1]) != STAT_NOACTION) { | |
| needbind = true; | |
| } | |
| xfd->stream.dtype = XIODATA_RECVFROM_SKIPIP_ONE; | |
| if ((result = | |
| _xioopen_dgram_recvfrom(&xfd->stream, xioflags, needbind?&us.soa:NULL, | |
| uslen, opts, pf, socktype, ipproto, E_ERROR)) | |
| != STAT_OK) { | |
| return result; | |
| } | |
| _xio_openlate(&xfd->stream, opts); | |
| return STAT_OK; | |
| } | |
| static | |
| int xioopen_rawip_recv(int argc, const char *argv[], struct opt *opts, | |
| int xioflags, xiofile_t *xfd, unsigned groups, | |
| int pf, int socktype, int dummy3) { | |
| const char *protname = argv[1]; | |
| char *garbage; | |
| bool needbind = false; | |
| union sockaddr_union us; | |
| socklen_t uslen = sizeof(us); | |
| int ipproto; | |
| int result; | |
| if (argc != 2) { | |
| Error2("%s: wrong number of parameters (%d instead of 1)", | |
| argv[0], argc-1); | |
| return STAT_NORETRY; | |
| } | |
| if ((ipproto = strtoul(protname, &garbage, 0)) >= 256) { | |
| Error2("xioopen_rawip_recv(\"%s\",,): protocol number exceeds 255 (%u)", | |
| protname, ipproto); | |
| return STAT_NORETRY; | |
| } else if (*garbage) { | |
| Warn1("xioopen_rawip_recv(\"%s\",,): trailing garbage in protocol specification", | |
| protname); | |
| /*return STAT_NORETRY;*/ | |
| } | |
| retropt_socket_pf(opts, &pf); | |
| if (pf == PF_UNSPEC) { | |
| #if WITH_IP4 && WITH_IP6 | |
| pf = xioopts.default_ip=='6'?PF_INET6:PF_INET; | |
| #elif WITH_IP6 | |
| pf = PF_INET6; | |
| #else | |
| pf = PF_INET; | |
| #endif | |
| } | |
| if (retropt_bind(opts, pf, socktype, ipproto, | |
| &/*us.soa*/xfd->stream.para.socket.la.soa, &uslen, 1, | |
| xfd->stream.para.socket.ip.res_opts[0], | |
| xfd->stream.para.socket.ip.res_opts[1]) == | |
| STAT_OK) { | |
| needbind = true; | |
| } else { | |
| /* pf is required during xioread checks */ | |
| xfd->stream.para.socket.la.soa.sa_family = pf; | |
| } | |
| xfd->stream.dtype = XIODATA_RECV_SKIPIP; | |
| result = | |
| _xioopen_dgram_recv(&xfd->stream, xioflags, | |
| needbind?&/*us.soa*/xfd->stream.para.socket.la.soa:NULL, | |
| uslen, | |
| opts, pf, socktype, ipproto, E_ERROR); | |
| _xio_openlate(&xfd->stream, opts); | |
| return result; | |
| } | |
| #endif /* (WITH_IP4 || WITH_IP6) && WITH_RAWIP */ |