mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-22 11:36:21 +00:00
Make mip-pcap work on Mac
This commit is contained in:
1 parent
9dea02e578
commit
b2624f6055
5 files changed
+220
-148
No files matched your search
@@ -0,0 +1,47 @@
|
||||
#MIP TCP / IP stack over pcap
|
||||
|
||||
This example allows to use Mongoose's MIP built-in TCP/IP stack on systems
|
||||
that support pcap API, i.e. have libpcap library installed. The application
|
||||
opens an interface and uses `pcap_next_ex()` for reading packets from the
|
||||
interface, and `pcap_inject()` to write packets to the interface.
|
||||
|
||||
NOTE: depending on the libcap implementation, the injected packets may
|
||||
or may not be looped back to the interface's TCP/IP stack. If they are
|
||||
not looped back, then it is necessary to create a separate interface that
|
||||
is bridged to the target interface - see MacOS example below.
|
||||
|
||||
## MacOS setup
|
||||
|
||||
MacOS has support for `feth` (fake ethernet) interfaces. One can create a pair
|
||||
of `feth` interfaces and interlink them. Once a `feth` interface is assigned
|
||||
a peer and an IP address, anything that gets injected to it, appears on a
|
||||
peer interface and vice versa.
|
||||
|
||||
```sh
|
||||
$ sudo ifconfig feth0 create
|
||||
$ sudo ifconfig feth1 create
|
||||
$ sudo ifconfig feth1 peer feth 0 # Link two fake ethernet ifaces together
|
||||
$ sudo ifconfig feth1 10.10 # Assign 10.0.0.10 to feth1
|
||||
$ sudo ifconfig feth0 up
|
||||
$ sudo ifconfig feth1 up
|
||||
```
|
||||
|
||||
Now we have two Ethernet interfaces, `feth0` and `feth1`, interlinked and active.
|
||||
On your Mac, go to "System Preferences" / Sharing, enable "Internet Sharing"
|
||||
and choose "Thunderbolt bridge". This enables DHCP on the `bridge0` interface.
|
||||
On my system it gets `192.168.2.1` IP address, and serves `192.168.2/24` net.
|
||||
which is bridge for all Thunderbolt devices, and adds necessary routes to the
|
||||
WiFi interface. We should add one of our fake interfaces to this bridge:
|
||||
|
||||
```sh
|
||||
$ sudo ifconfig bridge0 addm feth1
|
||||
```
|
||||
|
||||
We cat start an example using the `feth0`:
|
||||
|
||||
```sh
|
||||
$ make -C examples/mip-pcap/ clean all ARGS="-i feth0"
|
||||
...
|
||||
2386718 3 mip.c:279:arp_cache_add ARP cache: added 0xc0a80201 @ 36:77:4d:be:e0:80
|
||||
2386718 2 mip.c:300:onstatechange READY, IP: 192.168.2.17
|
||||
```
|
||||
+51
-40
@@ -6,45 +6,22 @@
|
||||
#include <pcap.h>
|
||||
#include "mongoose.h"
|
||||
|
||||
static struct mg_connection *s_sntp_conn = NULL;
|
||||
#define MQTT_URL "mqtt://broker.hivemq.com:1883" // MQTT broker to connect to
|
||||
#define MQTT_TOPIC "t/123" // Topic to subscribe to
|
||||
|
||||
static int s_signo;
|
||||
void signal_handler(int signo) {
|
||||
s_signo = signo;
|
||||
}
|
||||
|
||||
// SNTP client callback
|
||||
static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_SNTP_TIME) {
|
||||
int64_t t = *(int64_t *) ev_data;
|
||||
MG_INFO(("Got SNTP time: %lld ms from epoch", t));
|
||||
} else if (ev == MG_EV_CLOSE) {
|
||||
s_sntp_conn = NULL;
|
||||
}
|
||||
(void) fn_data, (void) c;
|
||||
}
|
||||
|
||||
// Called every 5 seconds. Increase that for production case.
|
||||
static void timer_fn(void *arg) {
|
||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
||||
if (s_sntp_conn == NULL) s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL);
|
||||
if (s_sntp_conn != NULL) mg_sntp_request(s_sntp_conn);
|
||||
}
|
||||
|
||||
static int fail(const char *fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
static size_t pcap_tx(const void *data, size_t len, void *userdata) {
|
||||
int res = pcap_inject((pcap_t *) userdata, data, len);
|
||||
static size_t pcap_tx(const void *buf, size_t len, void *userdata) {
|
||||
int res = pcap_inject((pcap_t *) userdata, buf, len);
|
||||
if (res == PCAP_ERROR) {
|
||||
MG_ERROR(("pcap_inject: %d", res));
|
||||
}
|
||||
return len;
|
||||
MG_INFO(("TX %lu", len));
|
||||
// mg_hexdump(buf, len);
|
||||
return res == PCAP_ERROR ? 0 : len;
|
||||
}
|
||||
|
||||
static bool pcap_up(void *userdata) {
|
||||
@@ -58,21 +35,43 @@ static size_t pcap_rx(void *buf, size_t len, void *userdata) {
|
||||
if (pcap_next_ex((pcap_t *) userdata, &hdr, &pkt) == 1) {
|
||||
received = hdr->len < len ? hdr->len : len;
|
||||
memcpy(buf, pkt, received);
|
||||
MG_INFO(("RX %lu", received));
|
||||
// mg_hexdump(buf, received);
|
||||
}
|
||||
return received;
|
||||
}
|
||||
|
||||
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_HTTP_MSG) mg_http_reply(c, 200, NULL, "hi\n");
|
||||
(void) fn_data, (void) ev_data;
|
||||
}
|
||||
|
||||
// MQTT event handler function
|
||||
static void mfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) {
|
||||
if (ev == MG_EV_CONNECT && mg_url_is_ssl(MQTT_URL)) {
|
||||
struct mg_tls_opts opts = {.ca = "ca.pem",
|
||||
.srvname = mg_url_host(MQTT_URL)};
|
||||
mg_tls_init(c, &opts);
|
||||
} else if (ev == MG_EV_MQTT_OPEN) {
|
||||
c->is_hexdumping = 1;
|
||||
mg_mqtt_sub(c, mg_str(MQTT_TOPIC), 2);
|
||||
} else if (ev == MG_EV_MQTT_MSG) {
|
||||
struct mg_mqtt_message *mm = ev_data;
|
||||
MG_INFO(("%.*s", (int) mm->data.len, mm->data.ptr));
|
||||
} else if (ev == MG_EV_MQTT_CMD) {
|
||||
struct mg_mqtt_message *mm = (struct mg_mqtt_message *) ev_data;
|
||||
MG_DEBUG(("cmd %d qos %d", mm->cmd, mm->qos));
|
||||
} else if (ev == MG_EV_CLOSE) {
|
||||
}
|
||||
(void) fn_data;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
const char *iface = "lo0"; // Network iface
|
||||
const char *mac = "aa:bb:cc:01:02:03"; // MAC address
|
||||
const char *mac = "00:00:01:02:03:77"; // MAC address
|
||||
const char *bpf = NULL; // "host x.x.x.x or ether host ff:ff:ff:ff:ff:ff";
|
||||
char errbuf[PCAP_ERRBUF_SIZE] = "";
|
||||
|
||||
struct mg_mgr mgr; // Event manager
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
||||
mg_timer_add(&mgr, 3000, MG_TIMER_REPEAT | MG_TIMER_RUN_NOW, timer_fn, &mgr);
|
||||
|
||||
// Parse options
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-i") == 0 && i + 1 < argc) {
|
||||
@@ -82,7 +81,8 @@ int main(int argc, char *argv[]) {
|
||||
} else if (strcmp(argv[i], "-bpf") == 0 && i + 1 < argc) {
|
||||
bpf = argv[++i];
|
||||
} else {
|
||||
return fail("unknown option %s", argv[i]);
|
||||
MG_ERROR(("unknown option %s", argv[i]));
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,21 +97,27 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
pcap_freealldevs(devs);
|
||||
}
|
||||
fail("pcap_open_live: %s\n", errbuf);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
pcap_setnonblock(ph, 1, errbuf);
|
||||
pcap_setdirection(ph, PCAP_D_IN);
|
||||
|
||||
// Apply BPF to reduce noise. Let in only broadcasts and our own traffic
|
||||
if (bpf != NULL) {
|
||||
struct bpf_program bpfp;
|
||||
if (pcap_compile(ph, &bpfp, bpf, 1, 0)) fail("compile \n");
|
||||
if (pcap_compile(ph, &bpfp, bpf, 1, 0)) MG_ERROR(("BPF compile failed\n"));
|
||||
pcap_setfilter(ph, &bpfp);
|
||||
pcap_freecode(&bpfp);
|
||||
}
|
||||
MG_INFO(("Opened interface %s\n", iface));
|
||||
|
||||
MG_INFO(("Opened interface %s", iface));
|
||||
signal(SIGINT, signal_handler);
|
||||
signal(SIGTERM, signal_handler);
|
||||
|
||||
struct mg_mgr mgr; // Event manager
|
||||
mg_mgr_init(&mgr); // Initialise event manager
|
||||
mg_log_set(MG_LL_DEBUG); // Set debug log level
|
||||
|
||||
struct mip_cfg c = {.ip = 0, .mask = 0, .gw = 0};
|
||||
sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &c.mac[0], &c.mac[1], &c.mac[2],
|
||||
&c.mac[3], &c.mac[4], &c.mac[5]);
|
||||
@@ -120,6 +126,11 @@ int main(int argc, char *argv[]) {
|
||||
mip_init(&mgr, &c, &driver, ph);
|
||||
MG_INFO(("Init done, starting main loop"));
|
||||
|
||||
mg_http_listen(&mgr, "http://0.0.0.0:8000", fn, NULL);
|
||||
|
||||
struct mg_mqtt_opts opts = {0};
|
||||
// mg_mqtt_connect(&mgr, MQTT_URL, &opts, mfn, NULL);
|
||||
|
||||
while (s_signo == 0) mg_mgr_poll(&mgr, 1); // Infinite event loop
|
||||
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
Reference in new issue
Block a user