mirror of
https://repo.or.cz/socat.git
synced 2024-12-22 15:32:35 +00:00
143 lines
4.4 KiB
C
143 lines
4.4 KiB
C
/* source: xio-ip4.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 IP4 related functions */
|
|
|
|
#include "xiosysincludes.h"
|
|
|
|
#if WITH_IP4
|
|
|
|
#include "xioopen.h"
|
|
#include "xio-socket.h"
|
|
#include "xio-ip.h"
|
|
#include "xio-ip4.h"
|
|
|
|
|
|
int xioparsenetwork_ip4(
|
|
const char *rangename,
|
|
struct xiorange *range,
|
|
const int ai_flags[2],
|
|
const unsigned long res_opts[2])
|
|
{
|
|
struct in_addr *netaddr_in = &range->netaddr.ip4.sin_addr;
|
|
struct in_addr *netmask_in = &range->netmask.ip4.sin_addr;
|
|
char *rangename1; /* a copy of rangename with writing allowed */
|
|
char *delimpos; /* absolute address of delimiter */
|
|
unsigned int bits; /* netmask bits */
|
|
union sockaddr_union sau;
|
|
socklen_t socklen = sizeof(sau);
|
|
int rc;
|
|
|
|
if ((rangename1 = strdup(rangename)) == NULL) {
|
|
Error1("strdup(\"%s\"): out of memory", rangename);
|
|
return STAT_RETRYLATER;
|
|
}
|
|
|
|
if (delimpos = strchr(rangename1, '/')) {
|
|
char *endptr;
|
|
bits = strtoul(delimpos+1, &endptr, 10);
|
|
if (! ((*(delimpos+1) != '\0') && (*endptr == '\0'))) {
|
|
Error1("not a valid IPv4 netmask in \"%s\"", rangename);
|
|
bits = 32; /* most secure selection */
|
|
} else if (bits > 32) {
|
|
Error1("IPv4 netmask \"%s\" is too large", rangename);
|
|
bits = 32;
|
|
}
|
|
if (bits <= 0) {
|
|
netmask_in->s_addr = 0;
|
|
} else {
|
|
netmask_in->s_addr = htonl((0xffffffff << (32-bits)));
|
|
}
|
|
} else if (delimpos = strchr(rangename1, ':')) {
|
|
if ((rc = xioresolve(delimpos+1, NULL, PF_INET, 0, 0,
|
|
&sau, &socklen, ai_flags, res_opts))
|
|
!= STAT_OK) {
|
|
return rc;
|
|
}
|
|
netmask_in->s_addr = sau.ip4.sin_addr.s_addr;
|
|
} else {
|
|
Error1("xioparsenetwork_ip4(\"%s\",,): missing netmask delimiter", rangename);
|
|
free(rangename1);
|
|
return STAT_NORETRY;
|
|
}
|
|
{
|
|
*delimpos = 0;
|
|
if ((rc = xioresolve(rangename1, NULL, PF_INET, 0, 0,
|
|
&sau, &socklen, ai_flags, res_opts))
|
|
!= STAT_OK) {
|
|
return rc;
|
|
}
|
|
netaddr_in->s_addr = sau.ip4.sin_addr.s_addr;
|
|
}
|
|
free(rangename1);
|
|
return STAT_OK;
|
|
}
|
|
|
|
/* check if peer address is within permitted range.
|
|
return >= 0 if so. */
|
|
int xiocheckrange_ip4(struct sockaddr_in *pa, struct xiorange *range) {
|
|
struct in_addr *netaddr_in = &range->netaddr.ip4.sin_addr;
|
|
struct in_addr *netmask_in = &range->netmask.ip4.sin_addr;
|
|
char addrbuf[256], maskbuf[256];
|
|
char peername[256];
|
|
|
|
/* is provided client address valid? */
|
|
if (pa->sin_addr.s_addr == 0) {
|
|
Warn("invalid client address 0.0.0.0");
|
|
return -1;
|
|
}
|
|
/* client address restriction */
|
|
Debug2("permitted client subnet: %s:%s",
|
|
inet4addr_info(ntohl(netaddr_in->s_addr), addrbuf, sizeof(addrbuf)),
|
|
inet4addr_info(ntohl(netmask_in->s_addr), maskbuf, sizeof(maskbuf)));
|
|
Debug1("client address is 0x%08x",
|
|
ntohl(pa->sin_addr.s_addr));
|
|
Debug1("masked address is 0x%08x",
|
|
ntohl(pa->sin_addr.s_addr & netmask_in->s_addr));
|
|
if ((pa->sin_addr.s_addr & netmask_in->s_addr)
|
|
!= netaddr_in->s_addr) {
|
|
Debug1("client address %s is not permitted",
|
|
sockaddr_inet4_info(pa, peername, sizeof(peername)));
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* returns information that can be used for constructing an environment
|
|
variable describing the socket address.
|
|
if idx is 0, this function writes "ADDR" into namebuff and the IP address
|
|
into valuebuff, and returns 1 (which means that one more info is there).
|
|
if idx is 1, it writes "PORT" into namebuff and the port number into
|
|
valuebuff, and returns 0 (no more info)
|
|
namelen and valuelen contain the max. allowed length of output chars in the
|
|
respective buffer.
|
|
on error this function returns -1.
|
|
*/
|
|
int
|
|
xiosetsockaddrenv_ip4(int idx, char *namebuff, size_t namelen,
|
|
char *valuebuff, size_t valuelen,
|
|
struct sockaddr_in *sa, int ipproto) {
|
|
switch (idx) {
|
|
case 0:
|
|
strcpy(namebuff, "ADDR");
|
|
inet4addr_info(ntohl(sa->sin_addr.s_addr), valuebuff, valuelen);
|
|
switch (ipproto) {
|
|
case IPPROTO_TCP:
|
|
case IPPROTO_UDP:
|
|
#ifdef IPPROTO_SCTP
|
|
case IPPROTO_SCTP:
|
|
#endif
|
|
return 1; /* there is port information to also be retrieved */
|
|
default:
|
|
return 0; /* no port info coming */
|
|
}
|
|
case 1:
|
|
strcpy(namebuff, "PORT");
|
|
snprintf(valuebuff, valuelen, "%u", ntohs(sa->sin_port));
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
#endif /* WITH_IP4 */
|