mirror of
https://repo.or.cz/socat.git
synced 2025-07-08 13:36:32 +00:00
DTLS over UDP
This commit is contained in:
parent
ff8de6c5cd
commit
d1b809b4ab
14 changed files with 537 additions and 126 deletions
193
xio-udp.c
193
xio-udp.c
|
@ -74,16 +74,11 @@ const struct addrdesc addr_udp6_recv = { "udp6-recv", 1, xioopen_udp_re
|
|||
#endif /* WITH_IP6 */
|
||||
|
||||
|
||||
/* we expect the form: port */
|
||||
int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *fd,
|
||||
unsigned groups, int pf, int ipproto,
|
||||
int protname) {
|
||||
const char *portname = argv[1];
|
||||
union sockaddr_union us;
|
||||
int _xioopen_ipdgram_listen(struct single *sfd,
|
||||
int xioflags, union sockaddr_union *us, socklen_t uslen,
|
||||
struct opt *opts, int pf, int socktype, int ipproto) {
|
||||
union sockaddr_union themunion;
|
||||
union sockaddr_union *them = &themunion;
|
||||
int socktype = SOCK_DGRAM;
|
||||
struct pollfd readfd;
|
||||
bool dofork = false;
|
||||
int maxchildren = 0;
|
||||
|
@ -91,49 +86,9 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
char *rangename;
|
||||
char infobuff[256];
|
||||
unsigned char buff1[1];
|
||||
socklen_t uslen;
|
||||
socklen_t themlen;
|
||||
int result;
|
||||
|
||||
if (argc != 2) {
|
||||
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
retropt_socket_pf(opts, &pf);
|
||||
|
||||
if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
uslen = socket_init(pf, &us);
|
||||
retropt_bind(opts, pf, socktype, IPPROTO_UDP,
|
||||
(struct sockaddr *)&us, &uslen, 1,
|
||||
fd->stream.para.socket.ip.res_opts[1],
|
||||
fd->stream.para.socket.ip.res_opts[0]);
|
||||
|
||||
if (false) {
|
||||
;
|
||||
#if WITH_IP4
|
||||
} else if (pf == PF_INET) {
|
||||
us.ip4.sin_port = parseport(portname, ipproto);
|
||||
#endif
|
||||
#if WITH_IP6
|
||||
} else if (pf == PF_INET6) {
|
||||
us.ip6.sin6_port = parseport(portname, ipproto);
|
||||
#endif
|
||||
} else {
|
||||
Error1("xioopen_ipdgram_listen(): unknown address family %d", pf);
|
||||
}
|
||||
|
||||
retropt_bool(opts, OPT_FORK, &dofork);
|
||||
|
||||
if (dofork) {
|
||||
|
@ -152,24 +107,24 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
#if WITH_IP4 /*|| WITH_IP6*/
|
||||
if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
|
||||
if (xioparserange(rangename, pf, &fd->stream.para.socket.range) < 0) {
|
||||
if (xioparserange(rangename, pf, &sfd->para.socket.range) < 0) {
|
||||
free(rangename);
|
||||
return STAT_NORETRY;
|
||||
}
|
||||
free(rangename);
|
||||
fd->stream.para.socket.dorange = true;
|
||||
sfd->para.socket.dorange = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if WITH_LIBWRAP
|
||||
xio_retropt_tcpwrap(&fd->stream, opts);
|
||||
xio_retropt_tcpwrap(sfd, opts);
|
||||
#endif /* WITH_LIBWRAP */
|
||||
|
||||
if (retropt_ushort(opts, OPT_SOURCEPORT, &fd->stream.para.socket.ip.sourceport)
|
||||
if (retropt_ushort(opts, OPT_SOURCEPORT, &sfd->para.socket.ip.sourceport)
|
||||
>= 0) {
|
||||
fd->stream.para.socket.ip.dosourceport = true;
|
||||
sfd->para.socket.ip.dosourceport = true;
|
||||
}
|
||||
retropt_bool(opts, OPT_LOWPORT, &fd->stream.para.socket.ip.lowport);
|
||||
retropt_bool(opts, OPT_LOWPORT, &sfd->para.socket.ip.lowport);
|
||||
|
||||
if (dofork) {
|
||||
xiosetchilddied(); /* set SIGCHLD handler */
|
||||
|
@ -184,40 +139,46 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
union sockaddr_union _sockname;
|
||||
union sockaddr_union *la = &_sockname; /* local address */
|
||||
|
||||
if ((fd->stream.fd = xiosocket(opts, pf, socktype, ipproto, E_ERROR)) < 0) {
|
||||
if ((sfd->fd = xiosocket(opts, pf, socktype, ipproto, E_ERROR)) < 0) {
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
doreuseaddr |= (retropt_int(opts, OPT_SO_REUSEADDR, &reuseaddr) >= 0);
|
||||
applyopts(fd->stream.fd, opts, PH_PASTSOCKET);
|
||||
applyopts(sfd->fd, opts, PH_PASTSOCKET);
|
||||
if (doreuseaddr) {
|
||||
if (Setsockopt(fd->stream.fd, opt_so_reuseaddr.major,
|
||||
if (Setsockopt(sfd->fd, opt_so_reuseaddr.major,
|
||||
opt_so_reuseaddr.minor, &reuseaddr, sizeof(reuseaddr))
|
||||
< 0) {
|
||||
Warn6("setsockopt(%d, %d, %d, {%d}, "F_Zd"): %s",
|
||||
fd->stream.fd, opt_so_reuseaddr.major,
|
||||
sfd->fd, opt_so_reuseaddr.major,
|
||||
opt_so_reuseaddr.minor, reuseaddr, sizeof(reuseaddr),
|
||||
strerror(errno));
|
||||
}
|
||||
}
|
||||
applyopts_cloexec(fd->stream.fd, opts);
|
||||
applyopts(fd->stream.fd, opts, PH_PREBIND);
|
||||
applyopts(fd->stream.fd, opts, PH_BIND);
|
||||
if (Bind(fd->stream.fd, &us.soa, uslen) < 0) {
|
||||
Error4("bind(%d, {%s}, "F_socklen"): %s", fd->stream.fd,
|
||||
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)),
|
||||
applyopts_cloexec(sfd->fd, opts);
|
||||
applyopts(sfd->fd, opts, PH_PREBIND);
|
||||
applyopts(sfd->fd, opts, PH_BIND);
|
||||
if (Bind(sfd->fd, &us->soa, uslen) < 0) {
|
||||
Error4("bind(%d, {%s}, "F_socklen"): %s", sfd->fd,
|
||||
sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
|
||||
uslen, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
/* under some circumstances bind() fills sockaddr with interesting info. */
|
||||
if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) {
|
||||
if (Getsockname(sfd->fd, &us->soa, &uslen) < 0) {
|
||||
Error4("getsockname(%d, %p, {%d}): %s",
|
||||
fd->stream.fd, &us.soa, uslen, strerror(errno));
|
||||
sfd->fd, &us->soa, uslen, strerror(errno));
|
||||
}
|
||||
applyopts(fd->stream.fd, opts, PH_PASTBIND);
|
||||
applyopts(sfd->fd, opts, PH_PASTBIND);
|
||||
|
||||
Notice1("listening on UDP %s",
|
||||
sockaddr_info(&us.soa, uslen, infobuff, sizeof(infobuff)));
|
||||
readfd.fd = fd->stream.fd;
|
||||
if (ipproto == IPPROTO_UDP) {
|
||||
Notice1("listening on UDP %s",
|
||||
sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)));
|
||||
} else {
|
||||
Notice2("listening on PROTO%d %s", ipproto,
|
||||
sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)));
|
||||
}
|
||||
|
||||
readfd.fd = sfd->fd;
|
||||
readfd.events = POLLIN|POLLERR;
|
||||
while (xiopoll(&readfd, 1, NULL) < 0) {
|
||||
if (errno != EINTR) break;
|
||||
|
@ -225,12 +186,12 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
|
||||
themlen = socket_init(pf, them);
|
||||
do {
|
||||
result = Recvfrom(fd->stream.fd, buff1, 1, MSG_PEEK,
|
||||
result = Recvfrom(sfd->fd, buff1, 1, MSG_PEEK,
|
||||
&them->soa, &themlen);
|
||||
} while (result < 0 && errno == EINTR);
|
||||
if (result < 0) {
|
||||
Error5("recvfrom(%d, %p, 1, MSG_PEEK, {%s}, {"F_socklen"}): %s",
|
||||
fd->stream.fd, buff1,
|
||||
sfd->fd, buff1,
|
||||
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
|
@ -239,11 +200,14 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
Notice1("accepting UDP connection from %s",
|
||||
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)));
|
||||
|
||||
if (xiocheckpeer(&fd->stream, them, la) < 0) {
|
||||
if (xiocheckpeer(sfd, them, la) < 0) {
|
||||
Notice1("forbidding UDP connection from %s",
|
||||
sockaddr_info(&them->soa, themlen,
|
||||
infobuff, sizeof(infobuff)));
|
||||
/* drop packet */
|
||||
char buff[512];
|
||||
Recv(fd->stream.fd, buff, sizeof(buff), 0); /* drop packet */
|
||||
Close(fd->stream.fd);
|
||||
Recv(sfd->fd, buff, sizeof(buff), 0); /* drop packet */
|
||||
Close(sfd->fd);
|
||||
continue;
|
||||
}
|
||||
Info1("permitting UDP connection from %s",
|
||||
|
@ -264,8 +228,8 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
/* server: continue loop with socket()+recvfrom() */
|
||||
/* when we dont close this we get awkward behaviour on Linux 2.4:
|
||||
recvfrom gives 0 bytes with invalid socket address */
|
||||
if (Close(fd->stream.fd) < 0) {
|
||||
Info2("close(%d): %s", fd->stream.fd, strerror(errno));
|
||||
if (Close(sfd->fd) < 0) {
|
||||
Info2("close(%d): %s", sfd->fd, strerror(errno));
|
||||
}
|
||||
|
||||
while (maxchildren) {
|
||||
|
@ -279,35 +243,88 @@ int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
|||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} /* end of the big while loop */
|
||||
|
||||
applyopts(fd->stream.fd, opts, PH_CONNECT);
|
||||
if ((result = Connect(fd->stream.fd, &them->soa, themlen)) < 0) {
|
||||
applyopts(sfd->fd, opts, PH_CONNECT);
|
||||
if ((result = Connect(sfd->fd, &them->soa, themlen)) < 0) {
|
||||
Error4("connect(%d, {%s}, "F_socklen"): %s",
|
||||
fd->stream.fd,
|
||||
sfd->fd,
|
||||
sockaddr_info(&them->soa, themlen, infobuff, sizeof(infobuff)),
|
||||
themlen, strerror(errno));
|
||||
return STAT_RETRYLATER;
|
||||
}
|
||||
|
||||
/* set the env vars describing the local and remote sockets */
|
||||
if (Getsockname(fd->stream.fd, &us.soa, &uslen) < 0) {
|
||||
if (Getsockname(sfd->fd, &us->soa, &uslen) < 0) {
|
||||
Warn4("getsockname(%d, %p, {%d}): %s",
|
||||
fd->stream.fd, &us.soa, uslen, strerror(errno));
|
||||
sfd->fd, &us->soa, uslen, strerror(errno));
|
||||
}
|
||||
xiosetsockaddrenv("SOCK", &us, uslen, IPPROTO_UDP);
|
||||
xiosetsockaddrenv("SOCK", us, uslen, IPPROTO_UDP);
|
||||
xiosetsockaddrenv("PEER", them, themlen, IPPROTO_UDP);
|
||||
|
||||
fd->stream.howtoend = END_SHUTDOWN;
|
||||
applyopts_fchown(fd->stream.fd, opts);
|
||||
applyopts(fd->stream.fd, opts, PH_LATE);
|
||||
sfd->howtoend = END_SHUTDOWN;
|
||||
applyopts_fchown(sfd->fd, opts);
|
||||
applyopts(sfd->fd, opts, PH_LATE);
|
||||
|
||||
if ((result = _xio_openlate(&fd->stream, opts)) < 0)
|
||||
if ((result = _xio_openlate(sfd, opts)) < 0)
|
||||
return result;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* we expect the form: port */
|
||||
int xioopen_ipdgram_listen(int argc, const char *argv[], struct opt *opts,
|
||||
int xioflags, xiofile_t *fd,
|
||||
unsigned groups, int pf, int ipproto,
|
||||
int protname) {
|
||||
const char *portname = argv[1];
|
||||
union sockaddr_union us;
|
||||
int socktype = SOCK_DGRAM;
|
||||
socklen_t uslen;
|
||||
|
||||
if (argc != 2) {
|
||||
Error2("%s: wrong number of parameters (%d instead of 1)", argv[0], argc-1);
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
retropt_socket_pf(opts, &pf);
|
||||
retropt_int(opts, OPT_SO_PROTOTYPE, &ipproto);
|
||||
|
||||
if (applyopts_single(&fd->stream, opts, PH_INIT) < 0) return -1;
|
||||
applyopts(-1, opts, PH_INIT);
|
||||
|
||||
uslen = socket_init(pf, &us);
|
||||
retropt_bind(opts, pf, socktype, ipproto,
|
||||
(struct sockaddr *)&us, &uslen, 1,
|
||||
fd->stream.para.socket.ip.res_opts[1],
|
||||
fd->stream.para.socket.ip.res_opts[0]);
|
||||
|
||||
if (false) {
|
||||
;
|
||||
#if WITH_IP4
|
||||
} else if (pf == PF_INET) {
|
||||
us.ip4.sin_port = parseport(portname, ipproto);
|
||||
#endif
|
||||
#if WITH_IP6
|
||||
} else if (pf == PF_INET6) {
|
||||
us.ip6.sin6_port = parseport(portname, ipproto);
|
||||
#endif
|
||||
} else {
|
||||
Error1("xioopen_ipdgram_listen(): unknown address family %d", pf);
|
||||
}
|
||||
|
||||
return _xioopen_ipdgram_listen(&fd->stream, xioflags, &us, uslen,
|
||||
opts, pf, socktype, ipproto);
|
||||
}
|
||||
|
||||
static
|
||||
int xioopen_udp_sendto(int argc, const char *argv[], struct opt *opts,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue