diff --git a/src/cfgparse.c b/src/cfgparse.c index 9bdfb3e3d..90cc9b03b 100644 --- a/src/cfgparse.c +++ b/src/cfgparse.c @@ -795,11 +795,24 @@ int cfg_parse_global(const char *file, int linenum, char **args, int kwm) } if (args[1][0] == '/') { + struct sockaddr_un *sk = str2sun(args[1]); + if (!sk) { + Alert("parsing [%s:%d] : Socket path '%s' too long (max %d)\n", file, linenum, + args[1], (int)sizeof(sk->sun_path) - 1); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + logsrv.u.un = *sk; logsrv.u.addr.sa_family = AF_UNIX; - logsrv.u.un = *str2sun(args[1]); } else { + struct sockaddr_in *sk = str2sa(args[1]); + if (!sk) { + Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + logsrv.u.in = *sk; logsrv.u.addr.sa_family = AF_INET; - logsrv.u.in = *str2sa(args[1]); if (!logsrv.u.in.sin_port) logsrv.u.in.sin_port = htons(SYSLOG_PORT); } @@ -2950,6 +2963,7 @@ stats_error_parsing: curproxy->grace = val; } else if (!strcmp(args[0], "dispatch")) { /* dispatch address */ + struct sockaddr_in *sk; if (curproxy == &defproxy) { Alert("parsing [%s:%d] : '%s' not allowed in 'defaults' section.\n", file, linenum, args[0]); err_code |= ERR_ALERT | ERR_FATAL; @@ -2963,7 +2977,13 @@ stats_error_parsing: err_code |= ERR_ALERT | ERR_FATAL; goto out; } - curproxy->dispatch_addr = *str2sa(args[1]); + sk = str2sa(args[1]); + if (!sk) { + Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + curproxy->dispatch_addr = *sk; } else if (!strcmp(args[0], "balance")) { /* set balancing with optional algorithm */ if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) @@ -3024,6 +3044,8 @@ stats_error_parsing: } if (!defsrv) { + struct sockaddr_in *sk; + if ((newsrv = (struct server *)calloc(1, sizeof(struct server))) == NULL) { Alert("parsing [%s:%d] : out of memory.\n", file, linenum); err_code |= ERR_ALERT | ERR_ABORT; @@ -3060,9 +3082,15 @@ stats_error_parsing: } else newsrv->state |= SRV_MAPPORTS; - newsrv->addr = *str2sa(raddr); - newsrv->addr.sin_port = htons(realport); + sk = str2sa(raddr); free(raddr); + if (!sk) { + Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[2]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + newsrv->addr = *sk; + newsrv->addr.sin_port = htons(realport); newsrv->check_port = curproxy->defsrv.check_port; newsrv->inter = curproxy->defsrv.inter; @@ -3221,7 +3249,13 @@ stats_error_parsing: cur_arg += 2; } else if (!defsrv && !strcmp(args[cur_arg], "addr")) { - newsrv->check_addr = *str2sa(args[cur_arg + 1]); + struct sockaddr_in *sk = str2sa(args[cur_arg + 1]); + if (!sk) { + Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + newsrv->check_addr = *sk; cur_arg += 2; } else if (!strcmp(args[cur_arg], "port")) { @@ -3353,6 +3387,8 @@ stats_error_parsing: } else if (!defsrv && !strcmp(args[cur_arg], "source")) { /* address to which we bind when connecting */ int port_low, port_high; + struct sockaddr_in *sk; + if (!*args[cur_arg + 1]) { #if defined(CONFIG_HAP_CTTPROXY) || defined(CONFIG_HAP_LINUX_TPROXY) Alert("parsing [%s:%d] : '%s' expects [:[-]], and optional '%s' as argument.\n", @@ -3365,7 +3401,13 @@ stats_error_parsing: goto out; } newsrv->state |= SRV_BIND_SRC; - newsrv->source_addr = *str2sa_range(args[cur_arg + 1], &port_low, &port_high); + sk = str2sa_range(args[cur_arg + 1], &port_low, &port_high); + if (!sk) { + Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + newsrv->source_addr = *sk; if (port_low != port_high) { int i; @@ -3405,8 +3447,14 @@ stats_error_parsing: } else if (!strcmp(args[cur_arg + 1], "clientip")) { newsrv->state |= SRV_TPROXY_CIP; } else { + struct sockaddr_in *sk = str2sa(args[cur_arg + 1]); + if (!sk) { + Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + newsrv->tproxy_addr = *sk; newsrv->state |= SRV_TPROXY_ADDR; - newsrv->tproxy_addr = *str2sa(args[cur_arg + 1]); } global.last_checks |= LSTCHK_NETADM; #if !defined(CONFIG_HAP_LINUX_TPROXY) @@ -3558,11 +3606,24 @@ stats_error_parsing: } if (args[1][0] == '/') { + struct sockaddr_un *sk = str2sun(args[1]); + if (!sk) { + Alert("parsing [%s:%d] : Socket path '%s' too long (max %d)\n", file, linenum, + args[1], (int)sizeof(sk->sun_path) - 1); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + logsrv.u.un = *sk; logsrv.u.addr.sa_family = AF_UNIX; - logsrv.u.un = *str2sun(args[1]); } else { + struct sockaddr_in *sk = str2sa(args[1]); + if (!sk) { + Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + logsrv.u.in = *sk; logsrv.u.addr.sa_family = AF_INET; - logsrv.u.in = *str2sa(args[1]); if (!logsrv.u.in.sin_port) { logsrv.u.in.sin_port = htons(SYSLOG_PORT); @@ -3596,6 +3657,7 @@ stats_error_parsing: } else if (!strcmp(args[0], "source")) { /* address to which we bind when connecting */ int cur_arg; + struct sockaddr_in *sk; if (warnifnotcap(curproxy, PR_CAP_BE, file, linenum, args[0], NULL)) err_code |= ERR_WARN; @@ -3613,7 +3675,13 @@ stats_error_parsing: curproxy->iface_name = NULL; curproxy->iface_len = 0; - curproxy->source_addr = *str2sa(args[1]); + sk = str2sa(args[1]); + if (!sk) { + Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + curproxy->source_addr = *sk; curproxy->options |= PR_O_BIND_SRC; cur_arg = 2; @@ -3640,8 +3708,14 @@ stats_error_parsing: } else if (!strcmp(args[cur_arg + 1], "clientip")) { curproxy->options |= PR_O_TPXY_CIP; } else { + struct sockaddr_in *sk = str2sa(args[cur_arg + 1]); + if (!sk) { + Alert("parsing [%s:%d] : Unknown host in '%s'\n", file, linenum, args[cur_arg + 1]); + err_code |= ERR_ALERT | ERR_FATAL; + goto out; + } + curproxy->tproxy_addr = *sk; curproxy->options |= PR_O_TPXY_ADDR; - curproxy->tproxy_addr = *str2sa(args[cur_arg + 1]); } global.last_checks |= LSTCHK_NETADM; #if !defined(CONFIG_HAP_LINUX_TPROXY) diff --git a/src/standard.c b/src/standard.c index e9be0f97f..2e6893654 100644 --- a/src/standard.c +++ b/src/standard.c @@ -119,6 +119,7 @@ const char *limit_r(unsigned long n, char *buffer, int size, const char *alt) /* * converts to a struct sockaddr_un* which is locally allocated. * The format is "/path", where "/path" is a path to a UNIX domain socket. + * NULL is returned if the socket path is invalid (too long). */ struct sockaddr_un *str2sun(const char *str) { @@ -128,8 +129,7 @@ struct sockaddr_un *str2sun(const char *str) memset(&su, 0, sizeof(su)); strsz = strlen(str) + 1; if (strsz > sizeof(su.sun_path)) { - Alert("Socket path '%s' too long (max %d)\n", - str, (int)sizeof(su.sun_path) - 1); + return NULL; } else { su.sun_family = AF_UNIX; memcpy(su.sun_path, str, strsz); @@ -216,18 +216,20 @@ const char *invalid_domainchar(const char *name) { /* * converts to a struct sockaddr_in* which is locally allocated. * The format is "addr:port", where "addr" can be a dotted IPv4 address, - * a host name, or empty or "*" to indicate INADDR_ANY. + * a host name, or empty or "*" to indicate INADDR_ANY. NULL is returned + * if the host part cannot be resolved. */ struct sockaddr_in *str2sa(char *str) { static struct sockaddr_in sa; + struct sockaddr_in *ret = NULL; char *c; int port; memset(&sa, 0, sizeof(sa)); str = strdup(str); if (str == NULL) - goto out_nofree; + goto out; if ((c = strrchr(str,':')) != NULL) { *c++ = '\0'; @@ -240,20 +242,17 @@ struct sockaddr_in *str2sa(char *str) sa.sin_addr.s_addr = INADDR_ANY; } else if (!inet_pton(AF_INET, str, &sa.sin_addr)) { - struct hostent *he; - - if ((he = gethostbyname(str)) == NULL) { - Alert("Invalid server name: '%s'\n", str); - } - else - sa.sin_addr = *(struct in_addr *) *(he->h_addr_list); + struct hostent *he = gethostbyname(str); + if (!he) + goto out; + sa.sin_addr = *(struct in_addr *) *(he->h_addr_list); } sa.sin_port = htons(port); sa.sin_family = AF_INET; - + ret = &sa; + out: free(str); - out_nofree: - return &sa; + return ret; } /* @@ -263,18 +262,20 @@ struct sockaddr_in *str2sa(char *str) * port is set in the sockaddr_in. Thus, it is enough to check the size of the * returned range to know if an array must be allocated or not. The format is * "addr[:port[-port]]", where "addr" can be a dotted IPv4 address, a host - * name, or empty or "*" to indicate INADDR_ANY. + * name, or empty or "*" to indicate INADDR_ANY. NULL is returned if the host + * part cannot be resolved. */ struct sockaddr_in *str2sa_range(char *str, int *low, int *high) { static struct sockaddr_in sa; + struct sockaddr_in *ret = NULL; char *c; int portl, porth; memset(&sa, 0, sizeof(sa)); str = strdup(str); if (str == NULL) - goto out_nofree; + goto out; if ((c = strrchr(str,':')) != NULL) { char *sep; @@ -296,23 +297,21 @@ struct sockaddr_in *str2sa_range(char *str, int *low, int *high) sa.sin_addr.s_addr = INADDR_ANY; } else if (!inet_pton(AF_INET, str, &sa.sin_addr)) { - struct hostent *he; - - if ((he = gethostbyname(str)) == NULL) { - Alert("Invalid server name: '%s'\n", str); - } - else - sa.sin_addr = *(struct in_addr *) *(he->h_addr_list); + struct hostent *he = gethostbyname(str); + if (!he) + goto out; + sa.sin_addr = *(struct in_addr *) *(he->h_addr_list); } sa.sin_port = htons(portl); sa.sin_family = AF_INET; + ret = &sa; *low = portl; *high = porth; + out: free(str); - out_nofree: - return &sa; + return ret; } /* converts to a struct in_addr containing a network mask. It can be