|
@@ -4499,41 +4499,50 @@ static void close_all_listening_sockets(struct mg_context *ctx) {
|
|
|
free(ctx->listening_sockets);
|
|
|
}
|
|
|
|
|
|
+static int is_valid_port(unsigned int port) {
|
|
|
+ return port > 0 && port < 0xffff;
|
|
|
+}
|
|
|
+
|
|
|
// Valid listening port specification is: [ip_address:]port[s]
|
|
|
// Examples: 80, 443s, 127.0.0.1:3128, 1.2.3.4:8080s
|
|
|
// TODO(lsm): add parsing of the IPv6 address
|
|
|
static int parse_port_string(const struct vec *vec, struct socket *so) {
|
|
|
- int a, b, c, d, port, len;
|
|
|
+ unsigned int a, b, c, d, ch, len, port;
|
|
|
+#if defined(USE_IPV6)
|
|
|
+ char buf[100];
|
|
|
+#endif
|
|
|
|
|
|
// MacOS needs that. If we do not zero it, subsequent bind() will fail.
|
|
|
// Also, all-zeroes in the socket address means binding to all addresses
|
|
|
// for both IPv4 and IPv6 (INADDR_ANY and IN6ADDR_ANY_INIT).
|
|
|
memset(so, 0, sizeof(*so));
|
|
|
+ so->lsa.sin.sin_family = AF_INET;
|
|
|
|
|
|
- if (sscanf(vec->ptr, "%d.%d.%d.%d:%d%n", &a, &b, &c, &d, &port, &len) == 5) {
|
|
|
- // Bind to a specific IPv4 address
|
|
|
+ if (sscanf(vec->ptr, "%u.%u.%u.%u:%u%n", &a, &b, &c, &d, &port, &len) == 5) {
|
|
|
+ // Bind to a specific IPv4 address, e.g. 192.168.1.5:8080
|
|
|
so->lsa.sin.sin_addr.s_addr = htonl((a << 24) | (b << 16) | (c << 8) | d);
|
|
|
- } else if (sscanf(vec->ptr, "%d%n", &port, &len) != 1 ||
|
|
|
- len <= 0 ||
|
|
|
- len > (int) vec->len ||
|
|
|
- port < 1 ||
|
|
|
- port > 65535 ||
|
|
|
- (vec->ptr[len] && vec->ptr[len] != 's' &&
|
|
|
- vec->ptr[len] != 'r' && vec->ptr[len] != ',')) {
|
|
|
- return 0;
|
|
|
- }
|
|
|
-
|
|
|
- so->is_ssl = vec->ptr[len] == 's';
|
|
|
- so->ssl_redir = vec->ptr[len] == 'r';
|
|
|
+ so->lsa.sin.sin_port = htons((uint16_t) port);
|
|
|
#if defined(USE_IPV6)
|
|
|
- so->lsa.sin6.sin6_family = AF_INET6;
|
|
|
- so->lsa.sin6.sin6_port = htons((uint16_t) port);
|
|
|
-#else
|
|
|
- so->lsa.sin.sin_family = AF_INET;
|
|
|
- so->lsa.sin.sin_port = htons((uint16_t) port);
|
|
|
+ } else if (sscanf(vec->ptr, "[%49[^]]]:%d%n", buf, &port, &len) == 2 &&
|
|
|
+ inet_pton(AF_INET6, buf, &so->lsa.sin6.sin6_addr)) {
|
|
|
+ // IPv6 address, e.g. [3ffe:2a00:100:7031::1]:8080
|
|
|
+ so->lsa.sin6.sin6_family = AF_INET6;
|
|
|
+ so->lsa.sin6.sin6_port = htons((uint16_t) port);
|
|
|
#endif
|
|
|
+ } else if (sscanf(vec->ptr, "%u%n", &port, &len) == 1) {
|
|
|
+ // If only port is specified, bind to IPv4, INADDR_ANY
|
|
|
+ so->lsa.sin.sin_port = htons((uint16_t) port);
|
|
|
+ } else {
|
|
|
+ port = len = 0; // Parsing failure. Make port invalid.
|
|
|
+ }
|
|
|
|
|
|
- return 1;
|
|
|
+ ch = vec->ptr[len]; // Next character after the port number
|
|
|
+ so->is_ssl = ch == 's';
|
|
|
+ so->ssl_redir = ch == 'r';
|
|
|
+
|
|
|
+ // Make sure the port is valid and vector ends with 's', 'r' or ','
|
|
|
+ return is_valid_port(port) &&
|
|
|
+ (ch == '\0' || ch == 's' || ch == 'r' || ch == ',');
|
|
|
}
|
|
|
|
|
|
static int set_ports_option(struct mg_context *ctx) {
|
|
@@ -4548,7 +4557,7 @@ static int set_ports_option(struct mg_context *ctx) {
|
|
|
while (success && (list = next_option(list, &vec, NULL)) != NULL) {
|
|
|
if (!parse_port_string(&vec, &so)) {
|
|
|
cry(fc(ctx), "%s: %.*s: invalid port spec. Expecting list of: %s",
|
|
|
- __func__, (int) vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|p]");
|
|
|
+ __func__, (int) vec.len, vec.ptr, "[IP_ADDRESS:]PORT[s|r]");
|
|
|
success = 0;
|
|
|
} else if (so.is_ssl && ctx->ssl_ctx == NULL) {
|
|
|
cry(fc(ctx), "Cannot add SSL socket, is -ssl_certificate option set?");
|
|
@@ -4560,10 +4569,12 @@ static int set_ports_option(struct mg_context *ctx) {
|
|
|
setsockopt(so.sock, SOL_SOCKET, SO_REUSEADDR,
|
|
|
(void *) &on, sizeof(on)) != 0 ||
|
|
|
#if defined(USE_IPV6)
|
|
|
- setsockopt(so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &off,
|
|
|
- sizeof(off)) != 0 ||
|
|
|
+ (so.lsa.sa.sa_family == AF_INET6 &&
|
|
|
+ setsockopt(so.sock, IPPROTO_IPV6, IPV6_V6ONLY, (void *) &off,
|
|
|
+ sizeof(off)) != 0) ||
|
|
|
#endif
|
|
|
- bind(so.sock, &so.lsa.sa, sizeof(so.lsa)) != 0 ||
|
|
|
+ bind(so.sock, &so.lsa.sa, so.lsa.sa.sa_family == AF_INET ?
|
|
|
+ sizeof(so.lsa.sin) : sizeof(so.lsa)) != 0 ||
|
|
|
listen(so.sock, SOMAXCONN) != 0) {
|
|
|
cry(fc(ctx), "%s: cannot bind to %.*s: %d", __func__,
|
|
|
(int) vec.len, vec.ptr, ERRNO);
|