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:
parent
21719898e8
commit
915f888f3e
5 changed files with 110 additions and 9 deletions
|
@ -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
|
||||
*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue