1
0
Fork 0
mirror of https://github.com/warmcat/libwebsockets.git synced 2025-03-30 00:00:16 +01:00

sa46: network check

This adds a helper to test if an sa46 is on an sa46-based subnet.

The compare helper is adapted to say that non INET/INET6 addresses with
the same AF match.
This commit is contained in:
Andy Green 2020-10-05 08:21:28 +01:00
parent 21719898e8
commit 915f888f3e
5 changed files with 110 additions and 9 deletions

View file

@ -124,11 +124,28 @@ lws_interface_to_sa(int ipv6, const char *ifname, struct sockaddr_in *addr,
* \param sa46a: first
* \param sa46b: second
*
* Returns 0 if the address family and address are the same, otherwise nonzero.
* Returns 0 if the address family is INET or INET6 and the address is the same,
* or if the AF is the same but not INET or INET6, otherwise nonzero.
*/
LWS_VISIBLE LWS_EXTERN int
lws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b);
/**
* lws_sa46_on_net() - checks if an sa46 is on the subnet represented by another
*
* \param sa46a: first
* \param sa46_net: network
* \param net_len: length of network non-mask
*
* Returns 0 if sa46a belongs on network sa46_net/net_len
*
* If there is an ipv4 / v6 mismatch between the ip and the net, the ipv4
* address is promoted to ::ffff:x.x.x.x before the comparison.
*/
LWS_VISIBLE LWS_EXTERN int
lws_sa46_on_net(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46_net,
int net_len);
/*
* lws_parse_numeric_address() - converts numeric ipv4 or ipv6 to byte address
*

View file

@ -466,14 +466,9 @@ lws_adopt_descriptor_vhost(struct lws_vhost *vh, lws_adoption_type type,
struct lws *
lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info)
{
socklen_t slen = sizeof(sa46);
socklen_t slen = sizeof(lws_sockaddr46);
struct lws *new_wsi;
if (info->type & LWS_ADOPT_SOCKET &&
getpeername(info->fd.sockfd, (struct sockaddr *)&wsi->sa46_peer,
&slen) < 0)
lwsl_info("%s: getpeername failed\n", __func__);
#if defined(LWS_WITH_PEER_LIMITS)
struct lws_peer *peer = NULL;
@ -507,6 +502,11 @@ lws_adopt_descriptor_vhost_via_info(const lws_adopt_desc_t *info)
return NULL;
}
if (info->type & LWS_ADOPT_SOCKET &&
getpeername(info->fd.sockfd, (struct sockaddr *)&new_wsi->sa46_peer,
&slen) < 0)
lwsl_info("%s: getpeername failed\n", __func__);
#if defined(LWS_WITH_PEER_LIMITS)
if (peer)
lws_peer_add_wsi(info->vh->context, peer, new_wsi);

View file

@ -404,7 +404,10 @@ ads_known:
#endif
/* grab a copy for peer tracking */
wsi->sa46_peer = *psa;
#if defined(LWS_WITH_UNIX_SOCK)
if (!wsi->unix_skt)
#endif
memcpy(&wsi->sa46_peer, psa, n);
m = connect(wsi->desc.sockfd, (const struct sockaddr *)psa, n);
if (m == -1) {

View file

@ -870,7 +870,85 @@ lws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b)
return memcmp(&sa46a->sa6.sin6_addr, &sa46b->sa6.sin6_addr, 16);
#endif
return sa46a->sa4.sin_addr.s_addr != sa46b->sa4.sin_addr.s_addr;
if (sa46a->sa4.sin_family == AF_INET)
return sa46a->sa4.sin_addr.s_addr != sa46b->sa4.sin_addr.s_addr;
return 0;
}
int
lws_sa46_on_net(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46_net,
int net_len)
{
uint8_t mask = 0xff, norm[16];
const uint8_t *p1, *p2;
if (sa46a->sa4.sin_family == AF_INET) {
p1 = (uint8_t *)&sa46a->sa4.sin_addr;
if (sa46_net->sa4.sin_family == AF_INET6) {
/* ip is v4, net is v6, promote ip to v6 */
memset(norm, 0, 10);
norm[10] = norm[11] = 0xff;
norm[12] = p1[0];
norm[13] = p1[1];
norm[14] = p1[2];
norm[15] = p1[3];
p1 = norm;
}
#if defined(LWS_WITH_IPV6)
} else
if (sa46a->sa4.sin_family == AF_INET6) {
p1 = (uint8_t *)&sa46a->sa6.sin6_addr;
#endif
} else
return 1;
if (sa46_net->sa4.sin_family == AF_INET) {
p2 = (uint8_t *)&sa46_net->sa4.sin_addr;
if (sa46a->sa4.sin_family == AF_INET6) {
/* ip is v6, net is v4, promote net to v6 */
memset(norm, 0, 10);
norm[10] = norm[11] = 0xff;
norm[12] = p2[0];
norm[13] = p2[1];
norm[14] = p2[2];
norm[15] = p2[3];
p2 = norm;
/* because the mask length is for net v4 address */
net_len += 12 * 8;
}
#if defined(LWS_WITH_IPV6)
} else
if (sa46a->sa4.sin_family == AF_INET6) {
p2 = (uint8_t *)&sa46_net->sa6.sin6_addr;
#endif
} else
return 1;
while (net_len > 0) {
if (net_len < 8)
mask <<= 8 - net_len;
if (((*p1++) & mask) != ((*p2++) & mask))
return 1;
net_len -= 8;
}
return 0;
}
void
lws_sa46_copy_address(lws_sockaddr46 *sa46a, const void *in, int af)
{
sa46a->sa4.sin_family = af;
if (af == AF_INET)
memcpy(&sa46a->sa4.sin_addr, in, 4);
#if defined(LWS_WITH_IPV6)
else if (af == AF_INET6)
memcpy(&sa46a->sa6.sin6_addr, in, sizeof(sa46a->sa6.sin6_addr));
#endif
}
#if defined(LWS_WITH_SYS_STATE)

View file

@ -1131,6 +1131,9 @@ lws_parse(struct lws *wsi, unsigned char *buf, int *len);
int LWS_WARN_UNUSED_RESULT
lws_parse_urldecode(struct lws *wsi, uint8_t *_c);
void
lws_sa46_copy_address(lws_sockaddr46 *sa46a, const void *in, int af);
int LWS_WARN_UNUSED_RESULT
lws_http_action(struct lws *wsi);