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

@ -154,7 +154,7 @@ static t_stat net_attach(UNIT *uptr, char *cptr) {
char host[CBUFSIZE], port[CBUFSIZE];
t_stat r;
r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), "3000");
r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), "3000", NULL);
if (r != SCPE_OK)
return SCPE_ARG;
net_reset(&net_dev);

View file

@ -581,7 +581,7 @@ if (oldf & UNIT_ATT)
ipl_detach (uptr);
if ((sim_switches & SWMASK ('C')) ||
((sim_switches & SIM_SW_REST) && (oldf & UNIT_ACTV))) {
r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), NULL);
r = sim_parse_addr (cptr, host, sizeof(host), "localhost", port, sizeof(port), NULL, NULL);
if ((r != SCPE_OK) || (port[0] == '\0'))
return SCPE_ARG;
sprintf(hostport, "%s%s%s%s%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", host[0] ? ":" : "", port);
@ -597,7 +597,7 @@ if ((sim_switches & SWMASK ('C')) ||
uptr->DSOCKET = newsock;
}
else {
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL);
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL);
if (r != SCPE_OK)
return SCPE_ARG;
sprintf(hostport, "%s%s%s%s%s", strchr(host, ':') ? "[" : "", host, strchr(host, ':') ? "]" : "", host[0] ? ":" : "", port);

View file

@ -462,7 +462,7 @@ static t_stat sca_attach (UNIT *uptr, char *cptr)
detach_unit(&sca_unit);
if (do_listen) { /* if listen mode, string specifies port number (only; otherwise it's a dummy argument) */
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT);
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL);
if (r != SCPE_OK)
return r;
if ((0 == strcmp(port, cptr)) && (0 == strcmp(port, "dummy")))
@ -493,7 +493,7 @@ static t_stat sca_attach (UNIT *uptr, char *cptr)
if (! *cptr)
return SCPE_2FARG;
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT);
r = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), SCA_DEFAULT_PORT, NULL);
if (r != SCPE_OK)
return r;
if ((0 == strcmp(cptr, port)) && (0 == strcmp(host, ""))) {

View file

@ -565,7 +565,7 @@ t_stat dmc_setpeer (UNIT* uptr, int32 val, char* cptr, void* desc)
if (!cptr) return SCPE_IERR;
if (uptr->flags & UNIT_ATT) return SCPE_ALATT;
status = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL);
status = sim_parse_addr (cptr, host, sizeof(host), NULL, port, sizeof(port), NULL, NULL);
if (status != SCPE_OK)
return status;
if (host[0] == '\0')
@ -1588,8 +1588,7 @@ int dmc_get_receive_socket(CTLR *controller, int forRead)
{
char host[sizeof(controller->line->transmit_host)];
sim_parse_addr (controller->line->transmit_host, host, sizeof(host), NULL, NULL, 0, NULL);
if (strcmp(ipaddr, host))
if (sim_parse_addr (controller->line->transmit_host, host, sizeof(host), NULL, NULL, 0, NULL, ipaddr))
{
sim_debug(DBG_WRN, controller->device, "Received connection from unexpected source IP %s. Closing the connection.\n", ipaddr);
dmc_close_receive(controller, "Unathorized connection", ipaddr);

View file

@ -498,7 +498,7 @@ while (*cptr != 0) { /* do all mods */
return r;
}
else {
r = sim_parse_addr (gbuf, NULL, 0, NULL, NULL, 0, NULL);
r = sim_parse_addr (gbuf, NULL, 0, NULL, NULL, 0, NULL, NULL);
if (r == SCPE_OK) {
if (sim_con_tmxr.master) /* already open? */
sim_set_notelnet (0, NULL); /* close first */

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;

View file

@ -83,7 +83,7 @@
#endif
#endif
t_stat sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port);
t_stat sim_parse_addr (const char *cptr, char *host, size_t hostlen, const char *default_host, char *port, size_t port_len, const char *default_port, const char *validate_addr);
SOCKET sim_master_sock (const char *hostport, t_stat *parse_status);
SOCKET sim_connect_sock (const char *hostport, const char *default_host, const char *default_port);
SOCKET sim_accept_conn (SOCKET master, char **connectaddr);

View file

@ -791,8 +791,7 @@ for (i = 0; i < mp->lines; i++) { /* check each line in se
if (lp->destination) { /* Virtual Null Modem Cable? */
char host[CBUFSIZE];
sim_parse_addr (lp->destination, host, sizeof(host), NULL, NULL, 0, NULL);
if (strcmp(address, host)) {
if (sim_parse_addr (lp->destination, host, sizeof(host), NULL, NULL, 0, NULL, address)) {
tmxr_msg (newsock, "Rejecting connection from unexpected source\r\n");
sprintf (msg, "tmxr_poll_conn() - Rejecting line connection from: %s, Expected: %s", address, host);
tmxr_debug_trace_line (lp, msg);
@ -1459,7 +1458,7 @@ while (*tptr) {
continue;
}
cptr = get_glyph (gbuf, port, ';');
if (SCPE_OK != sim_parse_addr (port, NULL, 0, NULL, NULL, 0, NULL))
if (SCPE_OK != sim_parse_addr (port, NULL, 0, NULL, NULL, 0, NULL, NULL))
return SCPE_ARG;
if (cptr)
get_glyph (cptr, cptr, 0); /* upcase this string */