still quite broken but a good starting point
This commit is contained in:
commit
cbf4ff2ad5
8 changed files with 661 additions and 0 deletions
9
CMakeLists.txt
Normal file
9
CMakeLists.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
cmake_minimum_required(VERSION 3.18)
|
||||
|
||||
project('ifname')
|
||||
|
||||
add_executable(ifnow src/main.c src/tun.c src/now.c)
|
||||
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -ggdb")
|
||||
target_include_directories(ifnow PUBLIC ./include/)
|
||||
set_target_properties(ifnow PROPERTIES LINK_LIBRARIES -pthread)
|
33
README.md
Normal file
33
README.md
Normal file
|
@ -0,0 +1,33 @@
|
|||
# ifnow
|
||||
A Linux network interface device for communication over the ESP-Now wireless broadcast protocol.
|
||||
|
||||
NOTE: This is EXTREMELY work in progress and as it requires root permissions is not recommended to be run unmonitored.
|
||||
|
||||
# Build
|
||||
```
|
||||
git clone https://git.oit.cloud/morgan/ifnow.git
|
||||
cd ifnow
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ../
|
||||
make
|
||||
```
|
||||
|
||||
This should result in the `ifnow` binary in the build directory.
|
||||
|
||||
# Usage
|
||||
This is two steps, first setting up monitoring mode (using aircrack-ng in this method). You will need to determine
|
||||
your wireless interface name and replace if different from `wlp2s0` in the example. You will also want to set the
|
||||
channel to match the ESP32 configuration.
|
||||
|
||||
```
|
||||
sudo airmon-ng start wlp2s0
|
||||
sudo iw wlp2s0 set channel 1
|
||||
./ifnow wlp2s0mon now1 10.10.0.13
|
||||
```
|
||||
|
||||
The interface is now up as `now1` and you should be able to write to this interface. In theory `pcap` can
|
||||
be used to intercept raw packets but if used with LwIP on the ESP32 end, which can be accomplished with
|
||||
[esp_netif_now](https://git.oit.cloud/morgan/esp_netif_now), any IP stack should work. Has been testing
|
||||
with UDP and some [CoAP](https://libcoap.net). There are definitely still issues with parsing some incoming
|
||||
packets.
|
113
include/ifnow.h
Normal file
113
include/ifnow.h
Normal file
|
@ -0,0 +1,113 @@
|
|||
#ifndef __IFNOW_H__
|
||||
#define __IFNOW_H__
|
||||
|
||||
#define IFNOW_MAX_RECEIVE (512)
|
||||
#define DATARATE_1Mbps 0x02
|
||||
#define DATARATE_2Mbps 0x04
|
||||
#define DATARATE_6Mbps 0x0c
|
||||
#define DATARATE_9Mbps 0x12
|
||||
#define DATARATE_12Mbps 0x18
|
||||
#define DATARATE_18Mbps 0x24
|
||||
#define DATARATE_24Mbps 0x30
|
||||
#define DATARATE_36Mbps 0x48
|
||||
#define DATARATE_48Mbps 0x60
|
||||
#define DATARATE_54Mbps 0x6c
|
||||
|
||||
#define CHANNEL_freq_1 2412
|
||||
#define CHANNEL_freq_2 2417
|
||||
#define CHANNEL_freq_3 2422
|
||||
#define CHANNEL_freq_4 2427
|
||||
#define CHANNEL_freq_5 2432
|
||||
#define CHANNEL_freq_6 2437
|
||||
#define CHANNEL_freq_7 2442
|
||||
#define CHANNEL_freq_8 2447
|
||||
#define CHANNEL_freq_9 2452
|
||||
#define CHANNEL_freq_10 2457
|
||||
#define CHANNEL_freq_11 2462
|
||||
#define CHANNEL_freq_12 2467
|
||||
#define CHANNEL_freq_13 2472
|
||||
|
||||
#define WLAN_LEN 24
|
||||
#define ACTIONFRAME_HEADER_LEN 8
|
||||
#define VENDORSPECIFIC_CONTENT_LEN 7
|
||||
|
||||
struct IEEE80211_radiotap {
|
||||
uint8_t version;
|
||||
uint8_t pad;
|
||||
uint16_t length;
|
||||
uint32_t present;
|
||||
uint8_t flags;
|
||||
uint8_t datarate;
|
||||
uint16_t channel_freq;
|
||||
uint16_t channel_flags_quarter;
|
||||
};
|
||||
|
||||
#define IFNOW_RADIOTAP_DEFAULT() {\
|
||||
.version = 0,\
|
||||
.pad = 0,\
|
||||
.length = sizeof(struct IEEE80211_radiotap),\
|
||||
.present = 0x0000000e,\
|
||||
.flags = 0x10,\
|
||||
.datarate = DATARATE_6Mbps,\
|
||||
.channel_freq = CHANNEL_freq_1,\
|
||||
.channel_flags_quarter = 0x00c0,\
|
||||
}
|
||||
|
||||
struct IEEE80211_vendorspecific {
|
||||
uint8_t elementID;
|
||||
uint8_t length;
|
||||
uint8_t OUI[3];
|
||||
uint8_t type;
|
||||
uint8_t version;
|
||||
uint8_t payload[250];
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define IFNOW_VENDORSPECIFIC_DEFAULT() {\
|
||||
.elementID = 0xdd,\
|
||||
.OUI[0] = 0x18,\
|
||||
.OUI[1] = 0xfe,\
|
||||
.OUI[2] = 0x34,\
|
||||
.type = 0x04,\
|
||||
.version = 0x01,\
|
||||
}
|
||||
|
||||
struct IEEE80211_actionframe {
|
||||
uint8_t category_code;
|
||||
uint8_t OUI[3];
|
||||
uint8_t unknown_bytes[4];
|
||||
struct IEEE80211_vendorspecific content;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
#define IFNOW_ACTIONFRAME_DEFAULT() {\
|
||||
.category_code = 0x7f,\
|
||||
.OUI[0] = 0x18,\
|
||||
.OUI[1] = 0xfe,\
|
||||
.OUI[2] = 0x34,\
|
||||
}
|
||||
|
||||
struct IEEE80211_wlan {
|
||||
uint8_t type;
|
||||
uint8_t flags;
|
||||
uint16_t duration;
|
||||
uint8_t da[6];
|
||||
uint8_t sa[6];
|
||||
uint8_t bssid[6];
|
||||
uint16_t seq;
|
||||
struct IEEE80211_actionframe actionframe;
|
||||
uint32_t fcs;
|
||||
};
|
||||
|
||||
#define IFNOW_WLAN_DEFAULT() {\
|
||||
.type = 0xd0,\
|
||||
.flags = 0x00,\
|
||||
.duration = 0x0000,\
|
||||
.seq = 0x0280,\
|
||||
.fcs = 0x00000000,\
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
struct IEEE80211_radiotap radiotap;
|
||||
struct IEEE80211_wlan wlan;
|
||||
} ifnow_packet_t;
|
||||
|
||||
#endif // __IFNOW_H__
|
28
include/ifnow_now.h
Normal file
28
include/ifnow_now.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef __IFNOW_WLAN_H__
|
||||
#define __IFNOW_WLAN_H__
|
||||
|
||||
#include <linux/filter.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ifnow.h"
|
||||
|
||||
#define ERR_SOCKET_FAILED (-1)
|
||||
#define ERR_IOCTL_FAILED (-2)
|
||||
#define ERR_BIND_FAILED (-3)
|
||||
#define ERR_FILTER_FAILED (-4)
|
||||
|
||||
typedef int (*ifnow_now_receive_cb)(void *now_cfg, uint8_t *buf, uint32_t len);
|
||||
|
||||
typedef struct {
|
||||
int fd_if_socket;
|
||||
char *if_name;
|
||||
struct sock_fprog filter;
|
||||
pthread_t thread_id;
|
||||
ifnow_now_receive_cb receive;
|
||||
} ifnow_now_cfg_t;
|
||||
|
||||
int ifnow_now_init(ifnow_now_cfg_t *now_cfg);
|
||||
int ifnow_now_send(ifnow_now_cfg_t *now_cfg, uint8_t *buf, uint16_t len);
|
||||
|
||||
#endif
|
26
include/ifnow_tun.h
Normal file
26
include/ifnow_tun.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#ifndef __IFNOW_TUN_H__
|
||||
#define __IFNOW_TUN_H__
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/filter.h>
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ifnow.h"
|
||||
|
||||
typedef int (*ifnow_tun_receive_cb)(void *tun_cfg, uint8_t *buf, uint32_t len);
|
||||
|
||||
typedef struct {
|
||||
int fd_tuntap;
|
||||
int fd_netlink;
|
||||
struct in_addr addr;
|
||||
char *addr_s;
|
||||
char *if_name;
|
||||
pthread_t thread_id;
|
||||
ifnow_tun_receive_cb receive;
|
||||
} ifnow_tun_cfg_t;
|
||||
|
||||
int ifnow_tun_init(ifnow_tun_cfg_t *tun_cfg);
|
||||
int ifnow_tun_send(ifnow_tun_cfg_t *tun_cfg, uint8_t *buf, uint8_t len);
|
||||
|
||||
#endif
|
89
src/main.c
Normal file
89
src/main.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
#include <stdio.h>
|
||||
#include <strings.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "ifnow.h"
|
||||
#include "ifnow_now.h"
|
||||
#include "ifnow_tun.h"
|
||||
|
||||
ifnow_now_cfg_t now_cfg;
|
||||
ifnow_tun_cfg_t tun_cfg;
|
||||
|
||||
#define ANSI_FONT_COL_RESET "\x1b[0m"
|
||||
#define FONT_COL_CUSTOM_RED "\e[38;2;200;0;0m"
|
||||
#define FONT_COL_CUSTOM_GREEN "\e[38;2;0;200;0m"
|
||||
#define FONT_COL_CUSTOM_BLUE "\e[38;2;0;0;200m"
|
||||
#define BCKGRD_COL_CUSTOM_RED "\e[48;2;200;0;0m"
|
||||
#define BCKGRD_COL_CUSTOM_GREEN "\e[48;2;0;200;0m"
|
||||
#define BCKGRD_COL_CUSTOM_BLUE "\e[48;2;0;0;200m"
|
||||
|
||||
char *color_chart[] = {
|
||||
// NOW header
|
||||
BCKGRD_COL_CUSTOM_GREEN, // category version
|
||||
FONT_COL_CUSTOM_BLUE, FONT_COL_CUSTOM_BLUE, FONT_COL_CUSTOM_BLUE, // org identifier
|
||||
FONT_COL_CUSTOM_RED, FONT_COL_CUSTOM_RED, FONT_COL_CUSTOM_RED, FONT_COL_CUSTOM_RED, // random
|
||||
// Vendor Specific Header
|
||||
BCKGRD_COL_CUSTOM_GREEN, // Element ID
|
||||
BCKGRD_COL_CUSTOM_BLUE, // Length
|
||||
FONT_COL_CUSTOM_BLUE, FONT_COL_CUSTOM_BLUE, FONT_COL_CUSTOM_BLUE, // org identifier
|
||||
BCKGRD_COL_CUSTOM_BLUE, // Type
|
||||
BCKGRD_COL_CUSTOM_GREEN, // Version
|
||||
// Body
|
||||
NULL
|
||||
};
|
||||
uint8_t color_size = 15;
|
||||
|
||||
int ifnow_now_receive_callback(void *cfg, uint8_t *buf, uint32_t len) {
|
||||
ifnow_now_cfg_t *now_cfg = cfg;
|
||||
|
||||
printf("NOW receive_count: %d\n", len);
|
||||
for(uint16_t i = 0; i < len; i++) {
|
||||
printf("%s%02X"ANSI_FONT_COL_RESET" ", (i < color_size ? color_chart[i] : (buf[i] == 0x11 ? BCKGRD_COL_CUSTOM_RED : "")), buf[i]);
|
||||
if(i % 16 == 15) printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// TODO apply buf to actual structs of headers
|
||||
uint8_t bp = 57;
|
||||
int err = ifnow_tun_send(&tun_cfg, buf + bp, len - bp);
|
||||
if(err < 0) {
|
||||
perror("Failed to send over tunnel");
|
||||
}
|
||||
}
|
||||
|
||||
int ifnow_tun_receive_callback(void *cfg, uint8_t *buf, uint32_t len) {
|
||||
printf("TUN receive_count: %d\n", len);
|
||||
|
||||
for(uint32_t i = 0; i < len; i++) {
|
||||
printf("%02X ", buf[i]);
|
||||
if(i % 16 == 15) printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
int err = ifnow_now_send(&now_cfg, buf, len);
|
||||
if(err < 0) {
|
||||
perror("Failed to send over now");
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t main(int argc, char **argv) {
|
||||
// TODO handle arguments
|
||||
// * <now_if> wifi interface to listen for ESP-Now packets on
|
||||
// Interface should be in monitor mode
|
||||
// * <tun_if> name of new TUN interface
|
||||
// * <ip_addr> IP address for `now` interface
|
||||
|
||||
now_cfg.if_name = argv[1];
|
||||
now_cfg.receive = &ifnow_now_receive_callback;
|
||||
|
||||
tun_cfg.if_name = argv[2];
|
||||
tun_cfg.addr_s = argv[3];
|
||||
tun_cfg.receive = &ifnow_tun_receive_callback;
|
||||
|
||||
ifnow_now_init(&now_cfg);
|
||||
ifnow_tun_init(&tun_cfg);
|
||||
|
||||
while(1) {};
|
||||
|
||||
return 0;
|
||||
}
|
189
src/now.c
Normal file
189
src/now.c
Normal file
|
@ -0,0 +1,189 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <linux/if_packet.h>
|
||||
#include <net/ethernet.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "ifnow.h"
|
||||
#include "ifnow_now.h"
|
||||
|
||||
ifnow_packet_t packet;
|
||||
|
||||
int ifnow_now_send(ifnow_now_cfg_t *now_cfg, uint8_t *buf, uint16_t len) {
|
||||
struct IEEE80211_radiotap radiotap = IFNOW_RADIOTAP_DEFAULT();
|
||||
struct IEEE80211_actionframe action = IFNOW_ACTIONFRAME_DEFAULT();
|
||||
struct IEEE80211_vendorspecific vendor = IFNOW_VENDORSPECIFIC_DEFAULT();
|
||||
struct IEEE80211_wlan wlan = IFNOW_WLAN_DEFAULT();
|
||||
|
||||
memcpy(&packet.radiotap, &radiotap, sizeof(struct IEEE80211_radiotap));
|
||||
memcpy(&packet.wlan.actionframe, &action, sizeof(struct IEEE80211_actionframe));
|
||||
|
||||
memcpy(&packet.wlan.actionframe.content, &vendor, sizeof(struct IEEE80211_vendorspecific));
|
||||
memcpy(&packet.wlan.actionframe.content.payload, buf, len < 250 ? len : 250);
|
||||
packet.wlan.actionframe.content.length = len + 5;
|
||||
|
||||
memcpy(&packet.wlan.da, buf, 6);
|
||||
memcpy(&packet.wlan.sa, buf + 6, 6);
|
||||
memcpy(&packet.wlan.bssid, buf, 6);
|
||||
|
||||
printf("NOW: sending %d bytes\n", sizeof(packet));
|
||||
|
||||
for(uint16_t i = 0; i < sizeof(packet); i++) {
|
||||
printf("%02X ", ((uint8_t*)&packet)[i]);
|
||||
if(i % 16 == 15) printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
// TODO verify sendto vs send vs write
|
||||
int ret = sendto(now_cfg->fd_if_socket, &packet, sizeof(packet), 0, NULL, 0);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void *ifnow_thread_handle(void *arg) {
|
||||
ifnow_now_cfg_t *now_cfg = arg;
|
||||
|
||||
printf("starting ifnow_now thread.\n");
|
||||
|
||||
ssize_t receive_count = 0;
|
||||
uint8_t receive_buffer[IFNOW_MAX_RECEIVE];
|
||||
|
||||
while(1) {
|
||||
receive_count = recv(now_cfg->fd_if_socket, receive_buffer, IFNOW_MAX_RECEIVE, MSG_TRUNC);
|
||||
|
||||
if(receive_count > 0 && now_cfg->receive != NULL) {
|
||||
now_cfg->receive(now_cfg, receive_buffer, receive_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int ifnow_now_init(ifnow_now_cfg_t *now_cfg) {
|
||||
printf("Using interface: %s\n", now_cfg->if_name);
|
||||
|
||||
struct sockaddr_ll if_bind_addr;
|
||||
struct ifreq ifr;
|
||||
|
||||
now_cfg->fd_if_socket = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
|
||||
|
||||
if(now_cfg->fd_if_socket == -1) {
|
||||
perror("Failed to initialize IF socket.");
|
||||
|
||||
return ERR_SOCKET_FAILED;
|
||||
}
|
||||
|
||||
strncpy((char*)ifr.ifr_name, now_cfg->if_name, IFNAMSIZ);
|
||||
|
||||
int ioctrl_err = ioctl(now_cfg->fd_if_socket, SIOCGIFINDEX, &ifr);
|
||||
|
||||
if(ioctrl_err < 0) {
|
||||
perror("Failed to set io ctl on IF socket.");
|
||||
return ERR_IOCTL_FAILED;
|
||||
}
|
||||
|
||||
if_bind_addr.sll_family = PF_PACKET;
|
||||
if_bind_addr.sll_protocol = htons(ETH_P_ALL);
|
||||
if_bind_addr.sll_ifindex = ifr.ifr_ifindex;
|
||||
|
||||
int bind_err = bind(now_cfg->fd_if_socket, (struct sockaddr *)&if_bind_addr, sizeof(if_bind_addr));
|
||||
|
||||
if(bind_err < 0) {
|
||||
perror("Failed bind raw socket.");
|
||||
|
||||
return ERR_BIND_FAILED;
|
||||
}
|
||||
|
||||
now_cfg->filter.len = 53;
|
||||
|
||||
uint32_t MSB_dst = 0;
|
||||
uint32_t LSB_dst = 0;
|
||||
|
||||
uint32_t MSB_src = 0;
|
||||
uint32_t LSB_src = 0;
|
||||
|
||||
uint8_t jeq_dst = 0x30;
|
||||
uint8_t jeq_src = 0x30;
|
||||
|
||||
struct sock_filter temp_code[53] = {
|
||||
{ 0x30, 0, 0, 0x00000003 },
|
||||
{ 0x64, 0, 0, 0x00000008 },
|
||||
{ 0x7, 0, 0, 0x00000000 },
|
||||
{ 0x30, 0, 0, 0x00000002 },
|
||||
{ 0x4c, 0, 0, 0x00000000 },
|
||||
{ 0x2, 0, 0, 0x00000000 },
|
||||
{ 0x7, 0, 0, 0x00000000 },
|
||||
{ 0x50, 0, 0, 0x00000000 },
|
||||
{ 0x54, 0, 0, 0x000000fc },
|
||||
{ 0x15, 0, 42, 0x000000d0 },
|
||||
{ 0x40, 0, 0, 0x00000018 },
|
||||
{ 0x15, 0, 40, 0x7f18fe34 },
|
||||
{ 0x50, 0, 0, 0x00000020 },
|
||||
{ 0x15, 0, 38, 0x000000dd },
|
||||
{ 0x40, 0, 0, 0x00000021 },
|
||||
{ 0x54, 0, 0, 0x00ffffff },
|
||||
{ 0x15, 0, 35, 0x0018fe34 },
|
||||
{ 0x50, 0, 0, 0x00000025 },
|
||||
{ 0x15, 0, 33, 0x00000004 },
|
||||
{ 0x50, 0, 0, 0x00000000 },
|
||||
{ 0x45, 31, 0, 0x00000004 },
|
||||
{ 0x45, 0, 21, 0x00000008 },
|
||||
{ 0x50, 0, 0, 0x00000001 },
|
||||
{ 0x45, 0, 4, 0x00000001 },
|
||||
{ 0x40, 0, 0, 0x00000012 },
|
||||
{ jeq_dst, 0, 26, LSB_dst },
|
||||
{ 0x48, 0, 0, 0x00000010 },
|
||||
{ jeq_dst, 4, 24, MSB_dst },
|
||||
{ 0x40, 0, 0, 0x00000006 },
|
||||
{ jeq_dst, 0, 22, LSB_dst },
|
||||
{ 0x48, 0, 0, 0x00000004 },
|
||||
{ jeq_dst, 0, 20, MSB_dst },
|
||||
{ 0x50, 0, 0, 0x00000001 },
|
||||
{ 0x45, 0, 13, 0x00000002 },
|
||||
{ 0x45, 0, 4, 0x00000001 },
|
||||
{ 0x40, 0, 0, 0x0000001a },
|
||||
{ jeq_src, 0, 15, LSB_src },
|
||||
{ 0x48, 0, 0, 0x00000018 },
|
||||
{ jeq_src, 12, 13, MSB_src },
|
||||
{ 0x40, 0, 0, 0x00000012 },
|
||||
{ jeq_src, 0, 11, LSB_src },
|
||||
{ 0x48, 0, 0, 0x00000010 },
|
||||
{ jeq_src, 8, 9, MSB_src },
|
||||
{ 0x40, 0, 0, 0x00000006 },
|
||||
{ jeq_dst, 0, 7, LSB_dst },
|
||||
{ 0x48, 0, 0, 0x00000004 },
|
||||
{ jeq_dst, 0, 5, MSB_dst },
|
||||
{ 0x40, 0, 0, 0x0000000c },
|
||||
{ jeq_src, 0, 3, LSB_src },
|
||||
{ 0x48, 0, 0, 0x0000000a },
|
||||
{ jeq_src, 0, 1, MSB_src },
|
||||
{ 0x6, 0, 0, 0x00040000 },
|
||||
{ 0x6, 0, 0, 0x00000000 }
|
||||
};
|
||||
|
||||
now_cfg->filter.filter = (struct sock_filter*) malloc(sizeof(struct sock_filter)*now_cfg->filter.len);
|
||||
memcpy(now_cfg->filter.filter, temp_code, sizeof(struct sock_filter) * now_cfg->filter.len);
|
||||
|
||||
int sockopt_err = setsockopt(now_cfg->fd_if_socket, SOL_SOCKET, SO_ATTACH_FILTER, &now_cfg->filter, sizeof(now_cfg->filter));
|
||||
if(sockopt_err < 0) {
|
||||
perror("Failed to set BPF socket options.");
|
||||
|
||||
return ERR_FILTER_FAILED;
|
||||
}
|
||||
|
||||
struct IEEE80211_radiotap radiotap = IFNOW_RADIOTAP_DEFAULT();
|
||||
struct IEEE80211_wlan wlan = IFNOW_WLAN_DEFAULT();
|
||||
struct IEEE80211_actionframe actionframe = IFNOW_ACTIONFRAME_DEFAULT();
|
||||
struct IEEE80211_vendorspecific content = IFNOW_VENDORSPECIFIC_DEFAULT();
|
||||
|
||||
memcpy(&packet.radiotap, &radiotap, sizeof(struct IEEE80211_radiotap));
|
||||
memcpy(&packet.wlan, &wlan, sizeof(struct IEEE80211_wlan));
|
||||
memcpy(&packet.wlan.actionframe, &actionframe, sizeof(struct IEEE80211_actionframe));
|
||||
memcpy(&packet.wlan.actionframe.content, &content, sizeof(struct IEEE80211_vendorspecific));
|
||||
|
||||
printf("radiotap.channel_freq: %d\n", packet.radiotap.channel_freq);
|
||||
|
||||
|
||||
pthread_create(&now_cfg->thread_id, NULL, &ifnow_thread_handle, now_cfg);
|
||||
}
|
174
src/tun.c
Normal file
174
src/tun.c
Normal file
|
@ -0,0 +1,174 @@
|
|||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/if_tun.h>
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <net/if.h>
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "ifnow_tun.h"
|
||||
|
||||
// this is called from the ESP Now receive callback
|
||||
// it passes the contents received from the wifi interface
|
||||
int ifnow_tun_send(ifnow_tun_cfg_t *tun_cfg, uint8_t *buf, uint8_t len) {
|
||||
printf("tun: sending %d bytes to fd: %d\n", len, tun_cfg->fd_tuntap);
|
||||
|
||||
for(uint16_t i = 0; i < len; i++) {
|
||||
printf("%02X ", buf[i]);
|
||||
if(i % 16 == 15) printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
return write(tun_cfg->fd_tuntap, buf, len);
|
||||
}
|
||||
|
||||
void *ifnow_tun_thread_handle(void *arg) {
|
||||
ifnow_tun_cfg_t *tun_cfg = arg;
|
||||
|
||||
printf("starting ifnow_tun thread.\n");
|
||||
|
||||
ssize_t receive_count = 0;
|
||||
uint8_t receive_buffer[IFNOW_MAX_RECEIVE];
|
||||
|
||||
while(1) {
|
||||
receive_count = read(tun_cfg->fd_tuntap, &receive_buffer, IFNOW_MAX_RECEIVE);
|
||||
|
||||
if(receive_count > 0 && tun_cfg->receive != NULL) {
|
||||
tun_cfg->receive(tun_cfg, (uint8_t*)&receive_buffer, receive_count);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
int ifnow_tun_netlink_connect(ifnow_tun_cfg_t *tun_cfg) {
|
||||
struct sockaddr_nl netlink_socket;
|
||||
|
||||
tun_cfg->fd_netlink = socket(AF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_ROUTE);
|
||||
if(tun_cfg->fd_netlink < 0) {
|
||||
perror("Failed to get netlink socket");
|
||||
|
||||
return -4;
|
||||
}
|
||||
|
||||
memset(&netlink_socket, 0, sizeof(struct sockaddr_nl));
|
||||
netlink_socket.nl_family = AF_NETLINK;
|
||||
int err = bind(tun_cfg->fd_netlink, (struct sockaddr*) &netlink_socket, sizeof(struct sockaddr_nl));
|
||||
if(err < 0) {
|
||||
perror("Failed to bind netlink socket");
|
||||
|
||||
return -5;
|
||||
}
|
||||
}
|
||||
|
||||
int ifnow_tun_netlink_set_ip(ifnow_tun_cfg_t *tun_cfg) {
|
||||
struct {
|
||||
struct nlmsghdr header;
|
||||
struct ifaddrmsg content;
|
||||
char attributes_buf[64];
|
||||
} request;
|
||||
|
||||
struct rtattr *request_attr;
|
||||
size_t attributes_buf_avail = sizeof request.attributes_buf;
|
||||
|
||||
memset(&request, 0, sizeof request);
|
||||
request.header.nlmsg_type = RTM_NEWADDR;
|
||||
request.header.nlmsg_len = NLMSG_LENGTH(sizeof request.content);
|
||||
request.header.nlmsg_flags = NLM_F_REQUEST | NLM_F_EXCL | NLM_F_CREATE;
|
||||
request.content.ifa_index = if_nametoindex(tun_cfg->if_name);
|
||||
request.content.ifa_family = AF_INET;
|
||||
request.content.ifa_prefixlen = 32;
|
||||
|
||||
/* request.attributes[IFA_LOCAL] = address */
|
||||
request_attr = IFA_RTA(&request.content);
|
||||
|
||||
request_attr->rta_type = IFA_LOCAL;
|
||||
request_attr->rta_len = RTA_LENGTH(sizeof (struct in_addr));
|
||||
request.header.nlmsg_len += request_attr->rta_len;
|
||||
inet_pton(AF_INET, tun_cfg->addr_s, RTA_DATA(request_attr));
|
||||
|
||||
/* request.attributes[IFA_ADDRESS] = address */
|
||||
request_attr = RTA_NEXT(request_attr, attributes_buf_avail);
|
||||
|
||||
request_attr->rta_type = IFA_ADDRESS;
|
||||
request_attr->rta_len = RTA_LENGTH(sizeof (struct in_addr));
|
||||
request.header.nlmsg_len += request_attr->rta_len;
|
||||
inet_pton(AF_INET, tun_cfg->addr_s, RTA_DATA(request_attr));
|
||||
|
||||
if (send(tun_cfg->fd_netlink, &request, request.header.nlmsg_len, 0) == -1) {
|
||||
perror("Failed to connect netlink");
|
||||
|
||||
return -6;
|
||||
}
|
||||
}
|
||||
|
||||
int ifnow_tun_netlink_up(ifnow_tun_cfg_t *tun_cfg) {
|
||||
struct {
|
||||
struct nlmsghdr header;
|
||||
struct ifinfomsg content;
|
||||
} request;
|
||||
|
||||
printf("ifnow_tun_netlink_up: %s\n", tun_cfg->if_name);
|
||||
|
||||
memset(&request, 0, sizeof request);
|
||||
request.header.nlmsg_len = NLMSG_LENGTH(sizeof request.content);
|
||||
request.header.nlmsg_flags = NLM_F_REQUEST;
|
||||
request.header.nlmsg_type = RTM_NEWLINK;
|
||||
request.content.ifi_index = if_nametoindex(tun_cfg->if_name);
|
||||
request.content.ifi_flags = IFF_UP;
|
||||
request.content.ifi_change = 1;
|
||||
|
||||
if (send(tun_cfg->fd_netlink, &request, request.header.nlmsg_len, 0) == -1) {
|
||||
perror("Failed to send netlink up");
|
||||
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ifnow_tun_tuntap_connect(ifnow_tun_cfg_t *tun_cfg) {
|
||||
struct ifreq ifr;
|
||||
|
||||
tun_cfg->fd_tuntap = open("/dev/net/tun", O_RDWR | O_CLOEXEC);
|
||||
if(tun_cfg->fd_tuntap < 0) {
|
||||
perror("Failed to open /dev/net/tun");
|
||||
|
||||
return -2;
|
||||
}
|
||||
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
||||
|
||||
if(tun_cfg->if_name != NULL) {
|
||||
memcpy(ifr.ifr_name, tun_cfg->if_name, strlen(tun_cfg->if_name) + 1);
|
||||
}
|
||||
|
||||
int err = ioctl(tun_cfg->fd_tuntap, TUNSETIFF, &ifr);
|
||||
if(err < 0) {
|
||||
perror("Failed to set interface name");
|
||||
return -3;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int ifnow_tun_init(ifnow_tun_cfg_t *tun_cfg) {
|
||||
printf("tun_cfg->addr_s: %s\n", tun_cfg->addr_s);
|
||||
|
||||
int err = inet_pton(AF_INET, tun_cfg->addr_s, &tun_cfg->addr);
|
||||
if(err < 0) {
|
||||
perror("Failed to parse IP address");
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
ifnow_tun_tuntap_connect(tun_cfg);
|
||||
ifnow_tun_netlink_connect(tun_cfg);
|
||||
ifnow_tun_netlink_set_ip(tun_cfg);
|
||||
// TODO send netlink route request
|
||||
ifnow_tun_netlink_up(tun_cfg);
|
||||
|
||||
pthread_create(&tun_cfg->thread_id, NULL, &ifnow_tun_thread_handle, tun_cfg);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue