mirror of
https://github.com/simh/simh.git
synced 2026-01-29 05:01:25 +00:00
Added an optional validation argument to sim_parse_addr for callers which need to confirm incoming connections come from expected sources
This commit is contained in:
215
sim_sock.c
215
sim_sock.c
@@ -75,95 +75,6 @@ extern FILE *sim_log;
|
||||
sim_msg_sock send message to socket
|
||||
*/
|
||||
|
||||
/* OS independent routines
|
||||
|
||||
sim_parse_addr parse a hostname/ipaddress from port and apply defaults
|
||||
*/
|
||||
|
||||
/* sim_parse_addr host:port
|
||||
|
||||
Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
|
||||
If the host field contains one or more colon characters (i.e. it is an IPv6 address),
|
||||
the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)
|
||||
|
||||
Inputs:
|
||||
cptr = pointer to input string
|
||||
default_host
|
||||
= optional pointer to default host if none specified
|
||||
host_len = length of host buffer
|
||||
default_port
|
||||
= optional pointer to default host if none specified
|
||||
port_len = length of port buffer
|
||||
Outputs:
|
||||
host = pointer to buffer for IP address (may be NULL), 0 = none
|
||||
port = pointer to buffer for IP port (may be NULL), 0 = none
|
||||
result = status
|
||||
*/
|
||||
|
||||
t_stat sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host, char *port, size_t port_len, const char *default_port)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
char *hostp, *portp;
|
||||
char *endc;
|
||||
unsigned long portval;
|
||||
|
||||
if ((cptr == NULL) || (*cptr == 0))
|
||||
return SCPE_ARG;
|
||||
if ((host != NULL) && (host_len != 0))
|
||||
memset (host, 0, host_len);
|
||||
if ((port != NULL) && (port_len != 0))
|
||||
memset (port, 0, port_len);
|
||||
strncpy (gbuf, cptr, CBUFSIZE);
|
||||
hostp = gbuf; /* default addr */
|
||||
portp = NULL;
|
||||
if ((portp = strrchr (gbuf, ':')) && /* x:y? split */
|
||||
(NULL == strchr (portp, ']'))) {
|
||||
*portp++ = 0;
|
||||
if (*portp == '\0')
|
||||
portp = (char *)default_port;
|
||||
}
|
||||
else
|
||||
if (default_port)
|
||||
portp = (char *)default_port;
|
||||
else {
|
||||
portp = gbuf;
|
||||
hostp = NULL;
|
||||
}
|
||||
if (portp != NULL) {
|
||||
portval = strtoul(portp, &endc, 10);
|
||||
if ((*endc == '\0') && ((portval == 0) || (portval > 65535)))
|
||||
return SCPE_ARG; /* value too big */
|
||||
if (*endc != '\0') {
|
||||
struct servent *se = getservbyname(portp, "tcp");
|
||||
|
||||
if (se == NULL)
|
||||
return SCPE_ARG; /* invalid service name */
|
||||
}
|
||||
}
|
||||
if (port) /* port wanted? */
|
||||
if (portp != NULL) {
|
||||
if (strlen(portp) >= port_len)
|
||||
return SCPE_ARG; /* no room */
|
||||
else
|
||||
strcpy (port, portp);
|
||||
}
|
||||
if (hostp != NULL) {
|
||||
if (']' == hostp[strlen(hostp)-1]) {
|
||||
if ('[' != hostp[0])
|
||||
return SCPE_ARG; /* invalid domain literal */
|
||||
strcpy(hostp, hostp+1); /* remove brackets from domain literal host */
|
||||
hostp[strlen(hostp)-1] = '\0';
|
||||
}
|
||||
}
|
||||
if (host) /* host wanted? */
|
||||
if (hostp != NULL)
|
||||
if (strlen(hostp) >= host_len)
|
||||
return SCPE_ARG; /* no room */
|
||||
else
|
||||
strcpy (host, hostp);
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
/* First, all the non-implemented versions */
|
||||
|
||||
#if defined (__OS2__) && !defined (__EMX__)
|
||||
@@ -525,6 +436,128 @@ int load_ws2(void) {
|
||||
}
|
||||
#endif
|
||||
|
||||
/* OS independent routines
|
||||
|
||||
sim_parse_addr parse a hostname/ipaddress from port and apply defaults and
|
||||
optionally validate an address match
|
||||
*/
|
||||
|
||||
/* sim_parse_addr host:port
|
||||
|
||||
Presumption is that the input, if it doesn't contain a ':' character is a port specifier.
|
||||
If the host field contains one or more colon characters (i.e. it is an IPv6 address),
|
||||
the IPv6 address MUST be enclosed in square bracket characters (i.e. Domain Literal format)
|
||||
|
||||
Inputs:
|
||||
cptr = pointer to input string
|
||||
default_host
|
||||
= optional pointer to default host if none specified
|
||||
host_len = length of host buffer
|
||||
default_port
|
||||
= optional pointer to default host if none specified
|
||||
port_len = length of port buffer
|
||||
validate_addr = optional name/addr which is checked to be equivalent
|
||||
to the host result of parsing the other input. This
|
||||
address would usually be returned by sim_accept_conn.
|
||||
Outputs:
|
||||
host = pointer to buffer for IP address (may be NULL), 0 = none
|
||||
port = pointer to buffer for IP port (may be NULL), 0 = none
|
||||
result = status (SCPE_OK on complete success or SCPE_ARG if
|
||||
parsing can't happen due to bad syntax, a value is
|
||||
out of range, a result can't fit into a result buffer,
|
||||
a service name doesn't exist, or a validation name
|
||||
doesn't match the parsed host)
|
||||
*/
|
||||
|
||||
t_stat sim_parse_addr (const char *cptr, char *host, size_t host_len, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr)
|
||||
{
|
||||
char gbuf[CBUFSIZE];
|
||||
char *hostp, *portp;
|
||||
char *endc;
|
||||
unsigned long portval;
|
||||
|
||||
if ((cptr == NULL) || (*cptr == 0))
|
||||
return SCPE_ARG;
|
||||
if ((host != NULL) && (host_len != 0))
|
||||
memset (host, 0, host_len);
|
||||
if ((port != NULL) && (port_len != 0))
|
||||
memset (port, 0, port_len);
|
||||
strncpy (gbuf, cptr, CBUFSIZE);
|
||||
hostp = gbuf; /* default addr */
|
||||
portp = NULL;
|
||||
if ((portp = strrchr (gbuf, ':')) && /* x:y? split */
|
||||
(NULL == strchr (portp, ']'))) {
|
||||
*portp++ = 0;
|
||||
if (*portp == '\0')
|
||||
portp = (char *)default_port;
|
||||
}
|
||||
else
|
||||
if (default_port)
|
||||
portp = (char *)default_port;
|
||||
else {
|
||||
portp = gbuf;
|
||||
hostp = NULL;
|
||||
}
|
||||
if (portp != NULL) {
|
||||
portval = strtoul(portp, &endc, 10);
|
||||
if ((*endc == '\0') && ((portval == 0) || (portval > 65535)))
|
||||
return SCPE_ARG; /* numeric value too big */
|
||||
if (*endc != '\0') {
|
||||
struct servent *se = getservbyname(portp, "tcp");
|
||||
|
||||
if (se == NULL)
|
||||
return SCPE_ARG; /* invalid service name */
|
||||
}
|
||||
}
|
||||
if (port) /* port wanted? */
|
||||
if (portp != NULL) {
|
||||
if (strlen(portp) >= port_len)
|
||||
return SCPE_ARG; /* no room */
|
||||
else
|
||||
strcpy (port, portp);
|
||||
}
|
||||
if (hostp != NULL) {
|
||||
if (']' == hostp[strlen(hostp)-1]) {
|
||||
if ('[' != hostp[0])
|
||||
return SCPE_ARG; /* invalid domain literal */
|
||||
strcpy(hostp, hostp+1); /* remove brackets from domain literal host */
|
||||
hostp[strlen(hostp)-1] = '\0';
|
||||
}
|
||||
}
|
||||
if (host) /* host wanted? */
|
||||
if (hostp != NULL)
|
||||
if (strlen(hostp) >= host_len)
|
||||
return SCPE_ARG; /* no room */
|
||||
else
|
||||
strcpy (host, hostp);
|
||||
if (validate_addr) {
|
||||
struct addrinfo *ai_host, *ai_validate, *ai;
|
||||
t_stat status;
|
||||
|
||||
if (hostp == NULL)
|
||||
return SCPE_ARG;
|
||||
if (p_getaddrinfo(hostp, NULL, NULL, &ai_host))
|
||||
return SCPE_ARG;
|
||||
if (p_getaddrinfo(validate_addr, NULL, NULL, &ai_validate)) {
|
||||
p_freeaddrinfo (ai_host);
|
||||
return SCPE_ARG;
|
||||
}
|
||||
status = SCPE_ARG;
|
||||
for (ai = ai_host; ai != NULL; ai = ai->ai_next) {
|
||||
if ((ai->ai_addrlen == ai_validate->ai_addrlen) &&
|
||||
(ai->ai_family == ai_validate->ai_family) &&
|
||||
(0 == memcmp (ai->ai_addr, ai_validate->ai_addr, ai->ai_addrlen))) {
|
||||
status = SCPE_OK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
p_freeaddrinfo (ai_host);
|
||||
p_freeaddrinfo (ai_validate);
|
||||
return status;
|
||||
}
|
||||
return SCPE_OK;
|
||||
}
|
||||
|
||||
void sim_init_sock (void)
|
||||
{
|
||||
#if defined (_WIN32)
|
||||
@@ -624,7 +657,7 @@ t_stat r;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result = NULL;
|
||||
|
||||
r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL);
|
||||
r = sim_parse_addr (hostport, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL);
|
||||
if (parse_status)
|
||||
*parse_status = r;
|
||||
if (r != SCPE_OK)
|
||||
@@ -671,7 +704,7 @@ t_stat r;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *result = NULL;
|
||||
|
||||
r = sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port);
|
||||
r = sim_parse_addr (hostport, host, sizeof(host), default_host, port, sizeof(port), default_port, NULL);
|
||||
if (r != SCPE_OK)
|
||||
return newsock;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user