get public wan ip
commit
b3d1a72ffc
@ -0,0 +1,2 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
@ -0,0 +1,31 @@
|
|||||||
|
project(
|
||||||
|
'hetzner_ddns',
|
||||||
|
'c',
|
||||||
|
default_options : ['c_std=gnu11,c11']
|
||||||
|
)
|
||||||
|
|
||||||
|
sources = [
|
||||||
|
'src/main.c',
|
||||||
|
'src/config.c',
|
||||||
|
]
|
||||||
|
|
||||||
|
includes = include_directories('include')
|
||||||
|
|
||||||
|
args = [
|
||||||
|
'-Wall',
|
||||||
|
]
|
||||||
|
|
||||||
|
link_args = [
|
||||||
|
'-lubox',
|
||||||
|
'-lubus',
|
||||||
|
'-luci',
|
||||||
|
'-ltlsl',
|
||||||
|
]
|
||||||
|
|
||||||
|
executable(
|
||||||
|
meson.project_name(),
|
||||||
|
sources,
|
||||||
|
include_directories: includes,
|
||||||
|
c_args: args,
|
||||||
|
link_args: link_args,
|
||||||
|
)
|
||||||
@ -0,0 +1,6 @@
|
|||||||
|
#include <string.h>
|
||||||
|
#include <uci.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
@ -0,0 +1,178 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <endian.h>
|
||||||
|
#include <uci.h>
|
||||||
|
#include <libubus.h>
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <tlsl/str.h>
|
||||||
|
#include <tlsl/scoped.h>
|
||||||
|
#include <tlsl/net.h>
|
||||||
|
|
||||||
|
#define UBUS_TIMEOUT_MS 10000
|
||||||
|
|
||||||
|
static void do_ubus_free(struct ubus_context **ctx) {
|
||||||
|
if (*ctx)
|
||||||
|
ubus_free(*ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void do_uci_free(struct uci_context **ctx) {
|
||||||
|
if (*ctx)
|
||||||
|
uci_free_context(*ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEF_SCOPED_TYPE(blob_buf, struct blob_buf, (struct blob_buf) { 0 }, blob_buf_free)
|
||||||
|
DEF_SCOPED_TYPE(ubus_context, struct ubus_context *, NULL, do_ubus_free)
|
||||||
|
DEF_SCOPED_TYPE(uci_context, struct uci_context *, NULL, do_uci_free)
|
||||||
|
|
||||||
|
struct cidr {
|
||||||
|
struct tlsl_ipv4_addr addr;
|
||||||
|
uint32_t mask;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CIDR(BYTE0, BYTE1, BYTE2, BYTE3, LEN) { \
|
||||||
|
.addr = TLSL_IPV4_ADDR(BYTE0, BYTE1, BYTE2, BYTE3), \
|
||||||
|
.mask = TLSL_IPV4_NETMASK_U32(LEN), \
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool addr_is_private(const struct tlsl_ipv4_addr *addr) {
|
||||||
|
static const struct cidr s_private[] = {
|
||||||
|
CIDR(10,0,0,0, 8),
|
||||||
|
CIDR(172,16,0,0, 12),
|
||||||
|
CIDR(192,168,0,0, 16),
|
||||||
|
};
|
||||||
|
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < (sizeof(s_private) / sizeof(s_private[0])); i++) {
|
||||||
|
if ((addr->addr & s_private[i].mask) == s_private[i].addr.addr)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid for the lifetime of the uci_context
|
||||||
|
static str_view_t hddns_uci_get(
|
||||||
|
struct uci_context *ctx,
|
||||||
|
const char *package,
|
||||||
|
const char *section,
|
||||||
|
const char *option)
|
||||||
|
{
|
||||||
|
struct uci_ptr ptr;
|
||||||
|
|
||||||
|
memset(&ptr, 0, sizeof(ptr));
|
||||||
|
ptr.package = package;
|
||||||
|
ptr.section = section;
|
||||||
|
ptr.option = option;
|
||||||
|
|
||||||
|
if ((uci_lookup_ptr(ctx, &ptr, NULL, true) != UCI_OK)
|
||||||
|
|| !(ptr.flags & UCI_LOOKUP_COMPLETE)
|
||||||
|
|| !ptr.o
|
||||||
|
|| (ptr.o->type != UCI_TYPE_STRING))
|
||||||
|
return SVIEW_NULL;
|
||||||
|
|
||||||
|
return sview_from_cstr_unbounded(ptr.o->v.string);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void get_public_wan_ubus_cb(struct ubus_request *req, int type, struct blob_attr *msg) {
|
||||||
|
enum {
|
||||||
|
ATTR_IFSTATUS_IPV4,
|
||||||
|
__ATTR_IFSTATUS_COUNT,
|
||||||
|
};
|
||||||
|
static const struct blobmsg_policy s_ifstatus_policy[__ATTR_IFSTATUS_COUNT] = {
|
||||||
|
[ATTR_IFSTATUS_IPV4] = { .name = "ipv4-address", .type = BLOBMSG_TYPE_ARRAY },
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
ATTR_IPV4_ADDR,
|
||||||
|
__ATTR_IPV4_COUNT,
|
||||||
|
};
|
||||||
|
static const struct blobmsg_policy s_ipv4_policy[__ATTR_IPV4_COUNT] = {
|
||||||
|
[ATTR_IPV4_ADDR] = { .name = "address", .type = BLOBMSG_TYPE_STRING },
|
||||||
|
};
|
||||||
|
|
||||||
|
struct tlsl_ipv4_addr *out = (struct tlsl_ipv4_addr *)req->priv;
|
||||||
|
struct tlsl_ip_addr parsed;
|
||||||
|
int parse_res;
|
||||||
|
struct blob_attr *root_attrs[__ATTR_IFSTATUS_COUNT];
|
||||||
|
struct blob_attr *ipv4_attrs[__ATTR_IPV4_COUNT];
|
||||||
|
struct blob_attr *ipv4_tab_attr;
|
||||||
|
int rem;
|
||||||
|
|
||||||
|
(void)type;
|
||||||
|
|
||||||
|
if (blobmsg_parse(s_ifstatus_policy, __ATTR_IFSTATUS_COUNT, root_attrs, blobmsg_data(msg),
|
||||||
|
blobmsg_len(msg)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!root_attrs[ATTR_IFSTATUS_IPV4])
|
||||||
|
return;
|
||||||
|
|
||||||
|
blobmsg_for_each_attr(ipv4_tab_attr, root_attrs[ATTR_IFSTATUS_IPV4], rem) {
|
||||||
|
if (blobmsg_type(ipv4_tab_attr) != BLOBMSG_TYPE_TABLE)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (blobmsg_parse(s_ipv4_policy, __ATTR_IPV4_COUNT, ipv4_attrs, blobmsg_data(ipv4_tab_attr),
|
||||||
|
blobmsg_len(ipv4_tab_attr)))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!ipv4_attrs[ATTR_IPV4_ADDR])
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (tlsl_ip_addr_parse(blobmsg_get_string(ipv4_attrs[ATTR_IPV4_ADDR]), &parsed)
|
||||||
|
|| (parsed.l3proto != TLSL_L3PROTO_IPV4)
|
||||||
|
|| addr_is_private(&parsed.v4))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
*out = parsed.v4;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_public_wan_addr(struct ubus_context *ctx, struct tlsl_ipv4_addr *out) {
|
||||||
|
uint32_t id;
|
||||||
|
int res;
|
||||||
|
|
||||||
|
out->addr = 0;
|
||||||
|
if ((res = ubus_lookup_id(ctx, "network.interface.wan", &id)))
|
||||||
|
return res;
|
||||||
|
if ((res = ubus_invoke(ctx, id, "status", NULL, get_public_wan_ubus_cb, out, UBUS_TIMEOUT_MS)))
|
||||||
|
return res;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv) {
|
||||||
|
SCOPED(uci_context, uci_ctx);
|
||||||
|
SCOPED(ubus_context, ubus_ctx);
|
||||||
|
str_view_t wan_dev;
|
||||||
|
struct tlsl_ip_addr wan_addr;
|
||||||
|
|
||||||
|
if (!(uci_ctx = uci_alloc_context())) {
|
||||||
|
fprintf(stderr, "uci_alloc_context failed\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if (!(ubus_ctx = ubus_connect(NULL))) {
|
||||||
|
fprintf(stderr, "ubus_connect failed\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if (sview_is_null(wan_dev = hddns_uci_get(uci_ctx, "network", "wan", "device"))) {
|
||||||
|
// printf("uci_get failed\n");
|
||||||
|
// return 1;
|
||||||
|
// }
|
||||||
|
// printf("out: " SVIEW_PRI "\n", SVIEW_PRI_ARGS(wan_dev));
|
||||||
|
|
||||||
|
// I'll do ipv6 when virgin media starts actually supporting ipv6
|
||||||
|
wan_addr.l3proto = TLSL_L3PROTO_IPV4;
|
||||||
|
if (get_public_wan_addr(ubus_ctx, &wan_addr.v4) || !wan_addr.v4.addr) {
|
||||||
|
fprintf(stderr, "failed to get public wan ip\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
str_buf_t wan_buf;
|
||||||
|
wan_buf = tlsl_ip_addr_fmt(&wan_addr);
|
||||||
|
printf("wan=%s\n", wan_buf.ptr);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
Loading…
Reference in New Issue