1
0
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:
Mark Pizzolato
2012-12-09 12:12:09 -08:00
parent 822fedf8ce
commit 7f6a1af5bf
8 changed files with 135 additions and 104 deletions

View File

@@ -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;