diff --git a/include/h.h b/include/h.h index c6c13079a..6342aae73 100644 --- a/include/h.h +++ b/include/h.h @@ -1059,6 +1059,7 @@ extern int running_interactively(void); extern int terminal_supports_color(void); extern void skip_whitespace(char **p); extern void read_until(char **p, char *stopchars); +extern int is_ip_valid(const char *ip); /* src/unrealdb.c start */ extern UnrealDB *unrealdb_open(const char *filename, UnrealDBMode mode, char *secret_block); extern int unrealdb_close(UnrealDB *c); diff --git a/src/misc.c b/src/misc.c index 0e122b5e1..2c20f7a65 100644 --- a/src/misc.c +++ b/src/misc.c @@ -2344,3 +2344,19 @@ char *url_getfilename(const char *url) } return raw_strdup("-"); } + +/* + * Checks whether given string contains a valid IP address. + */ +int is_ip_valid(const char *ip) +{ + char scratch[64]; + if (BadPtr(ip)) + return 0; + if (inet_pton(AF_INET, ip, scratch) == 1) + return 1; + if (inet_pton(AF_INET6, ip, scratch) == 1) + return 1; + return 0; +} + diff --git a/src/modules/webirc.c b/src/modules/webirc.c index c9bf40db6..d8b645af4 100644 --- a/src/modules/webirc.c +++ b/src/modules/webirc.c @@ -350,8 +350,7 @@ void dowebirc(Client *client, char *ip, char *host, char *options) /* STEP 1: Update client->local->ip inet_pton() returns 1 on success, 0 on bad input, -1 on bad AF */ - if ((inet_pton(AF_INET, ip, scratch) != 1) && - (inet_pton(AF_INET6, ip, scratch) != 1)) + if (!is_ip_valid(ip)) { /* then we have an invalid IP */ exit_client(client, NULL, "Invalid IP address"); diff --git a/src/modules/websocket.c b/src/modules/websocket.c index 2f37d39f0..18b9f5f69 100644 --- a/src/modules/websocket.c +++ b/src/modules/websocket.c @@ -85,6 +85,7 @@ int websocket_create_packet(int opcode, char **buf, int *len); int websocket_send_pong(Client *client, char *buf, int len); int websocket_secure_connect(Client *client); struct HTTPForwardedHeader *websocket_parse_forwarded_header(char *input); +int websocket_ip_compare(const char *ip1, const char *ip2); /* Global variables */ ModDataInfo *websocket_md; @@ -183,11 +184,16 @@ int websocket_config_test(ConfigFile *cf, ConfigEntry *ce, int type, int *errs) { if (!cep->value) { - /* TODO check whether the ip/host is valid? */ config_error_empty(cep->file->filename, cep->line_number, "listen::options::websocket::forward", cep->name); errors++; continue; } + if (!is_ip_valid(cep->value)) + { + config_error("%s:%i: invalid IP address '%s' in listen::options::websocket::forward", cep->file->filename, cep->line_number, cep->value); + errors++; + continue; + } } else { config_error("%s:%i: unknown directive listen::options::websocket::%s", @@ -684,7 +690,7 @@ int websocket_handshake_valid(Client *client) if (WSU(client)->forwarded) { /* check for source ip */ - if (BadPtr(client->local->listener->websocket_forward) || 0 /* TODO add access checking here*/) + if (BadPtr(client->local->listener->websocket_forward) || !websocket_ip_compare(client->local->listener->websocket_forward, client->ip)) { unreal_log(ULOG_WARNING, "websocket", "UNAUTHORIZED_FORWARDED_HEADER", client, "Received unauthorized Forwarded header from $ip", log_data_string("ip", client->ip)); dead_socket(client, "Forwarded: no access"); @@ -694,8 +700,7 @@ int websocket_handshake_valid(Client *client) struct HTTPForwardedHeader *forwarded; forwarded = websocket_parse_forwarded_header(WSU(client)->forwarded); /* check header values */ - char scratch[64]; - if ((inet_pton(AF_INET, forwarded->ip, scratch) != 1) && (inet_pton(AF_INET6, forwarded->ip, scratch) != 1)) + if (!is_ip_valid(forwarded->ip)) { unreal_log(ULOG_WARNING, "websocket", "INVALID_FORWARDED_IP", client, "Received invalid IP in Forwarded header from $ip", log_data_string("ip", client->ip)); dead_socket(client, "Forwarded: invalid IP"); @@ -1165,3 +1170,33 @@ int websocket_send_pong(Client *client, char *buf, int len) send_queued(client); return 0; } + +/** Compare IP addresses (for authorization checking) */ +int websocket_ip_compare(const char *ip1, const char *ip2) +{ + uint32_t ip4[2]; + uint16_t ip6[16]; + int i; + if (inet_pton(AF_INET, ip1, &ip4[0]) == 1) /* IPv4 */ + { + if (inet_pton(AF_INET, ip2, &ip4[1]) == 1) /* both are valid, let's compare */ + { + return ip4[0] == ip4[1]; + } + return 0; + } + if (inet_pton(AF_INET6, ip1, &ip6[0]) == 1) /* IPv6 */ + { + if (inet_pton(AF_INET6, ip2, &ip6[8]) == 1) + { + for (i = 0; i < 8; i++) + { + if (ip6[i] != ip6[i+8]) + return 0; + } + return 1; + } + } + return 0; /* neither valid IPv4 nor IPv6 */ +} +