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

adopt: udp iface and AF_PACKET

This commit is contained in:
Andy Green 2019-10-05 12:47:42 +01:00
parent 70d2ca94b5
commit 3c95483518
9 changed files with 331 additions and 17 deletions

View file

@ -166,7 +166,9 @@ lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
lws_sockfd_type accept_fd, const char *readbuf,
size_t len);
#define LWS_CAUDP_BIND 1
#define LWS_CAUDP_BIND (1 << 0)
#define LWS_CAUDP_BROADCAST (1 << 1)
#define LWS_CAUDP_PF_PACKET (1 << 2)
#if defined(LWS_WITH_UDP)
/**
@ -177,6 +179,7 @@ lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
* \param port: UDP port to bind to, -1 means unbound
* \param flags: 0 or LWS_CAUDP_NO_BIND
* \param protocol_name: Name of protocol on vhost to bind wsi to
* \param ifname: NULL, for network interface name to bind socket to
* \param parent_wsi: NULL or parent wsi new wsi will be a child of
* \param retry_policy: NULL for vhost default policy else wsi specific policy
*
@ -185,7 +188,7 @@ lws_adopt_socket_vhost_readbuf(struct lws_vhost *vhost,
* */
LWS_VISIBLE LWS_EXTERN struct lws *
lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
int flags, const char *protocol_name,
int flags, const char *protocol_name, const char *ifname,
struct lws *parent_wsi, const lws_retry_bo_t *retry_policy);
#endif
///@}

View file

@ -430,18 +430,19 @@ lws_create_adopt_udp2(struct lws *wsi, const char *ads,
const struct addrinfo *r, int n, void *opaque)
{
lws_sock_file_fd_type sock;
int bc = 1;
assert(wsi);
if (!wsi->dns_results)
wsi->dns_results_next = wsi->dns_results = r;
if (n < 0 || !r) {
if (ads && (n < 0 || !r)) {
/*
* DNS lookup failed: there are no usable results. Fail the
* overall connection request.
*/
lwsl_debug("%s: bad: n %d, r %p\n", __func__, n, r);
lwsl_notice("%s: bad: n %d, r %p\n", __func__, n, r);
/*
* We didn't get a callback on a cache item and bump the
@ -464,27 +465,51 @@ lws_create_adopt_udp2(struct lws *wsi, const char *ads,
* function is for.
*/
#if !defined(__linux__)
/* PF_PACKET is linux-only */
sock.sockfd = socket(wsi->dns_results_next->ai_family,
SOCK_DGRAM, IPPROTO_UDP);
#else
sock.sockfd = socket(wsi->pf_packet ? PF_PACKET :
wsi->dns_results_next->ai_family,
SOCK_DGRAM, wsi->pf_packet ?
htons(0x800) : IPPROTO_UDP);
#endif
if (sock.sockfd == LWS_SOCK_INVALID)
goto resume;
((struct sockaddr_in *)wsi->dns_results_next->ai_addr)->sin_port =
htons(wsi->c_port);
if (setsockopt(sock.sockfd, SOL_SOCKET, SO_REUSEADDR, (const char *)&bc,
sizeof(bc)) < 0)
lwsl_err("%s: failed to set reuse\n", __func__);
if (wsi->do_broadcast &&
setsockopt(sock.sockfd, SOL_SOCKET, SO_BROADCAST, (const char *)&bc,
sizeof(bc)) < 0)
lwsl_err("%s: failed to set broadcast\n",
__func__);
/* Bind the udp socket to a particular network interface */
if (opaque &&
lws_plat_BINDTODEVICE(sock.sockfd, (const char *)opaque))
goto resume;
if (wsi->do_bind &&
bind(sock.sockfd, wsi->dns_results_next->ai_addr,
#if defined(_WIN32)
(int)wsi->dns_results_next->ai_addrlen
#else
wsi->dns_results_next->ai_addrlen
sizeof(struct sockaddr)//wsi->dns_results_next->ai_addrlen
#endif
) == -1) {
lwsl_notice("%s: bind failed\n", __func__);
lwsl_err("%s: bind failed\n", __func__);
goto resume;
}
if (!wsi->do_bind) {
((struct sockaddr_in *)wsi->dns_results_next->ai_addr)->
sin_port = htons(wsi->c_port);
if (!wsi->do_bind && !wsi->pf_packet) {
if (connect(sock.sockfd, wsi->dns_results_next->ai_addr,
wsi->dns_results_next->ai_addrlen) == -1) {
@ -514,7 +539,7 @@ resume:
wsi->dns_results_next = wsi->dns_results_next->ai_next;
}
lwsl_err("%s: unable to create INET socket\n", __func__);
lwsl_err("%s: unable to create INET socket %d\n", __func__, LWS_ERRNO);
lws_addrinfo_clean(wsi);
bail:
@ -525,7 +550,7 @@ bail:
struct lws *
lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
int flags, const char *protocol_name,
int flags, const char *protocol_name, const char *ifname,
struct lws *parent_wsi, const lws_retry_bo_t *retry_policy)
{
#if !defined(LWS_PLAT_OPTEE)
@ -543,6 +568,8 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
goto bail;
}
wsi->do_bind = !!(flags & LWS_CAUDP_BIND);
wsi->do_broadcast = !!(flags & LWS_CAUDP_BROADCAST);
wsi->pf_packet = !!(flags & LWS_CAUDP_PF_PACKET);
wsi->c_port = port;
if (retry_policy)
wsi->retry_policy = retry_policy;
@ -599,7 +626,7 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
*/
n = lws_async_dns_query(vhost->context, 0, ads,
LWS_ADNS_RECORD_A,
lws_create_adopt_udp2, wsi, NULL);
lws_create_adopt_udp2, wsi, (void *)ifname);
lwsl_debug("%s: dns query returned %d\n", __func__, n);
if (n == LADNS_RET_FAILED) {
lwsl_err("%s: async dns failed\n", __func__);
@ -611,8 +638,8 @@ lws_create_adopt_udp(struct lws_vhost *vhost, const char *ads, int port,
goto bail;
}
} else {
lwsl_debug("%s: fail on no ads\n", __func__);
wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, NULL);
lwsl_debug("%s: udp adopt has no ads\n", __func__);
wsi = lws_create_adopt_udp2(wsi, ads, NULL, 0, (void *)ifname);
}
/* dns lookup is happening asynchronously */

View file

@ -695,6 +695,8 @@ struct lws {
unsigned int h2_acked_settings:1;
unsigned int seen_nonpseudoheader:1;
unsigned int listener:1;
unsigned int pf_packet:1;
unsigned int do_broadcast:1;
unsigned int user_space_externally_allocated:1;
unsigned int socket_is_permanently_unusable:1;
unsigned int rxflow_change_to:2;

View file

@ -224,6 +224,44 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
return 1; // inet_pton(af, src, dst);
}
int
lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}
int
lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
int n, int fd, const char *iface)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}
int
lws_plat_if_up(const char *ifname, int fd, int up)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}
int
lws_plat_BINDTODEVICE(int fd, const char *ifname)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}
int
lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
uint8_t *gateway_ip)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}

View file

@ -55,6 +55,8 @@
#endif
#if defined(__linux__)
#include <endian.h>
#include <linux/if_packet.h>
#include <net/if.h>
#endif
#if defined(__QNX__)
#include <gulliver.h>
@ -147,6 +149,10 @@ wsi_from_fd(const struct lws_context *context, int fd);
int
insert_wsi(const struct lws_context *context, struct lws *wsi);
int
lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
uint8_t *gateway_ip);
void
delete_from_fd(const struct lws_context *context, int fd);
@ -174,3 +180,13 @@ delete_from_fd(const struct lws_context *context, int fd);
#if defined(__sun) && !defined(MSG_NOSIGNAL)
#define MSG_NOSIGNAL 0
#endif
int
lws_plat_BINDTODEVICE(int fd, const char *ifname);
int
lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
int n, int fd, const char *iface);
int
lws_plat_if_up(const char *ifname, int fd, int up);

View file

@ -25,6 +25,10 @@
#define _GNU_SOURCE
#include "private-lib-core.h"
#include <sys/ioctl.h>
#include <net/route.h>
#include <net/if.h>
#include <pwd.h>
#include <grp.h>
@ -266,3 +270,184 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
{
return inet_pton(af, src, dst);
}
int
lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
{
#if defined(__linux__)
struct ifreq i;
memset(&i, 0, sizeof(i));
lws_strncpy(i.ifr_name, ifname, sizeof(i.ifr_name));
if (ioctl(fd, SIOCGIFHWADDR, &i) < 0)
return -1;
memcpy(hwaddr, &i.ifr_hwaddr.sa_data, 6);
return 6;
#else
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
#endif
}
int
lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
int n, int fd, const char *iface)
{
#if defined(__linux__)
struct sockaddr_ll sll;
uint16_t *p16 = (uint16_t *)p;
uint32_t ucs = 0;
memcpy(p, canned, canned_len);
p[2] = n >> 8;
p[3] = n;
while (p16 < (uint16_t *)(p + 20))
ucs += ntohs(*p16++);
ucs += ucs >> 16;
ucs ^= 0xffff;
p[10] = ucs >> 8;
p[11] = ucs;
p[24] = (n - 20) >> 8;
p[25] = (n - 20);
memset(&sll, 0, sizeof(sll));
sll.sll_family = AF_PACKET;
sll.sll_protocol = htons(0x800);
sll.sll_halen = 6;
sll.sll_ifindex = if_nametoindex(iface);
memset(sll.sll_addr, 0xff, 6);
return sendto(fd, p, n, 0, (struct sockaddr *)&sll, sizeof(sll));
#else
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
#endif
}
int
lws_plat_if_up(const char *ifname, int fd, int up)
{
#if defined(__linux__)
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
lws_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
if (ioctl(fd, SIOCGIFFLAGS, &ifr) < 0) {
lwsl_err("%s: SIOCGIFFLAGS fail\n", __func__);
return 1;
}
if (up)
ifr.ifr_flags |= IFF_UP;
else
ifr.ifr_flags &= ~IFF_UP;
if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
lwsl_err("%s: SIOCSIFFLAGS fail\n", __func__);
return 1;
}
return 0;
#else
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
#endif
}
int
lws_plat_BINDTODEVICE(int fd, const char *ifname)
{
#if defined(__linux__)
struct ifreq i;
memset(&i, 0, sizeof(i));
i.ifr_addr.sa_family = AF_INET;
lws_strncpy(i.ifr_ifrn.ifrn_name, ifname,
sizeof(i.ifr_ifrn.ifrn_name));
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, &i, sizeof(i)) < 0) {
lwsl_notice("%s: failed %d\n", __func__, LWS_ERRNO);
return 1;
}
return 0;
#else
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
#endif
}
int
lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
uint8_t *gateway_ip)
{
#if defined(__linux__)
struct sockaddr_in *addr;
struct sockaddr_in sin;
struct rtentry route;
struct ifreq ifr;
memset(&ifr, 0, sizeof(ifr));
memset(&route, 0, sizeof(route));
memset(&sin, 0, sizeof(sin));
lws_strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
lws_plat_if_up(ifname, fd, 0);
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = htonl(*(uint32_t *)ip);
memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
if (ioctl(fd, SIOCSIFADDR, &ifr) < 0) {
lwsl_err("%s: SIOCSIFADDR fail\n", __func__);
return 1;
}
sin.sin_addr.s_addr = htonl(*(uint32_t *)mask_ip);
memcpy(&ifr.ifr_addr, &sin, sizeof(struct sockaddr));
if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
lwsl_err("%s: SIOCSIFNETMASK fail\n", __func__);
return 1;
}
lws_plat_if_up(ifname, fd, 1);
addr = (struct sockaddr_in *)&route.rt_gateway;
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = htonl(*(uint32_t *)gateway_ip);
addr = (struct sockaddr_in *)&route.rt_dst;
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = 0;
addr = (struct sockaddr_in *)&route.rt_genmask;
addr->sin_family = AF_INET;
addr->sin_addr.s_addr = 0;
route.rt_flags = RTF_UP | RTF_GATEWAY;
route.rt_metric = 100;
if (ioctl(fd, SIOCADDRT, &route) < 0) {
lwsl_err("%s: SIOCADDRT fail: %d\n", __func__, LWS_ERRNO);
return 1;
}
return 0;
#else
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
#endif
}

View file

@ -315,3 +315,46 @@ lws_plat_inet_pton(int af, const char *src, void *dst)
lws_free(buffer);
return ok ? 1 : -1;
}
int
lws_plat_ifname_to_hwaddr(int fd, const char *ifname, uint8_t *hwaddr, int len)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}
int
lws_plat_rawudp_broadcast(uint8_t *p, const uint8_t *canned, int canned_len,
int n, int fd, const char *iface)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}
int
lws_plat_if_up(const char *ifname, int fd, int up)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}
int
lws_plat_BINDTODEVICE(int fd, const char *ifname)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}
int
lws_plat_ifconfig_ip(const char *ifname, int fd, uint8_t *ip, uint8_t *mask_ip,
uint8_t *gateway_ip)
{
lwsl_err("%s: UNIMPLEMENTED on this platform\n", __func__);
return -1;
}

View file

@ -312,7 +312,7 @@ lws_async_dns_init(struct lws_context *context)
context->async_dns.wsi = lws_create_adopt_udp(context->vhost_list, ads,
53, 0, lws_async_dns_protocol.name, NULL,
&retry_policy);
NULL, &retry_policy);
if (!dns->wsi) {
lwsl_err("%s: foreign socket adoption failed\n", __func__);
return 1;

View file

@ -170,7 +170,7 @@ int main(int argc, const char **argv)
* Create our own "foreign" UDP socket bound to 7681/udp
*/
if (!lws_create_adopt_udp(vhost, NULL, 7681, LWS_CAUDP_BIND,
protocols[0].name, NULL, NULL)) {
protocols[0].name, NULL, NULL, NULL)) {
lwsl_err("%s: foreign socket adoption failed\n", __func__);
goto bail;
}