X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=libs%2Fluci-lib-ip%2Fsrc%2Fip.c;h=b91966c5369c78ba94065a31721176b68920a15b;hp=66ecb567ef5bb42fa2a4697f95346b23b9fdf004;hb=cd24ad05a4a87e5bb37a64a26a72e609b523c640;hpb=0ff02e3a13d11466fe8997932a7f9828f53f3ee8 diff --git a/libs/luci-lib-ip/src/ip.c b/libs/luci-lib-ip/src/ip.c index 66ecb567e..b91966c53 100644 --- a/libs/luci-lib-ip/src/ip.c +++ b/libs/luci-lib-ip/src/ip.c @@ -69,6 +69,7 @@ struct dump_filter { cidr_t from; cidr_t src; cidr_t dst; + struct ether_addr mac; }; struct dump_state { @@ -80,14 +81,14 @@ struct dump_state { }; -static int _cidr_new(lua_State *L, int index, int family); +static int _cidr_new(lua_State *L, int index, int family, bool mask); static cidr_t *L_checkcidr (lua_State *L, int index, cidr_t *p) { if (lua_type(L, index) == LUA_TUSERDATA) return luaL_checkudata(L, index, LUCI_IP_CIDR); - if (_cidr_new(L, index, p ? p->family : 0)) + if (_cidr_new(L, index, p ? p->family : 0, false)) return lua_touserdata(L, -1); luaL_error(L, "Invalid operand"); @@ -125,27 +126,23 @@ static bool parse_mask(int family, const char *mask, int *bits) static bool parse_cidr(const char *dest, cidr_t *pp) { - char *p, *a, buf[INET6_ADDRSTRLEN * 2 + 2]; + char *p, buf[INET6_ADDRSTRLEN * 2 + 2]; uint8_t bitlen = 0; strncpy(buf, dest, sizeof(buf) - 1); - a = buf; p = strchr(buf, '/'); if (p) *p++ = 0; - if (!strncasecmp(buf, "::ffff:", 7)) - a += 7; - - if (inet_pton(AF_INET, a, &pp->addr.v4)) + if (inet_pton(AF_INET, buf, &pp->addr.v4)) { bitlen = 32; pp->family = AF_INET; pp->len = sizeof(struct in_addr); } - else if (inet_pton(AF_INET6, a, &pp->addr.v6)) + else if (inet_pton(AF_INET6, buf, &pp->addr.v6)) { bitlen = 128; pp->family = AF_INET6; @@ -283,7 +280,7 @@ static int L_checkbits(lua_State *L, int index, cidr_t *p) return bits; } -static int _cidr_new(lua_State *L, int index, int family) +static int _cidr_new(lua_State *L, int index, int family, bool mask) { uint32_t n; const char *addr; @@ -298,10 +295,10 @@ static int _cidr_new(lua_State *L, int index, int family) cidr.family = AF_INET6; cidr.bits = 128; cidr.len = sizeof(cidr.addr.v6); - cidr.addr.v6.s6_addr[15] = n; - cidr.addr.v6.s6_addr[14] = (n >> 8); - cidr.addr.v6.s6_addr[13] = (n >> 16); - cidr.addr.v6.s6_addr[12] = (n >> 24); + cidr.addr.v6.s6_addr[12] = n; + cidr.addr.v6.s6_addr[13] = (n >> 8); + cidr.addr.v6.s6_addr[14] = (n >> 16); + cidr.addr.v6.s6_addr[15] = (n >> 24); } else { @@ -320,6 +317,9 @@ static int _cidr_new(lua_State *L, int index, int family) if (family && cidr.family != family) return 0; + + if (mask) + cidr.bits = L_checkbits(L, index + 1, &cidr); } if (!(cidrp = lua_newuserdata(L, sizeof(*cidrp)))) @@ -333,17 +333,17 @@ static int _cidr_new(lua_State *L, int index, int family) static int cidr_new(lua_State *L) { - return _cidr_new(L, 1, 0); + return _cidr_new(L, 1, 0, true); } static int cidr_ipv4(lua_State *L) { - return _cidr_new(L, 1, AF_INET); + return _cidr_new(L, 1, AF_INET, true); } static int cidr_ipv6(lua_State *L) { - return _cidr_new(L, 1, AF_INET6); + return _cidr_new(L, 1, AF_INET6, true); } static int cidr_is4(lua_State *L) @@ -379,6 +379,31 @@ static int cidr_is4linklocal(lua_State *L) return 1; } +static bool _is_mapped4(cidr_t *p) +{ + return (p->family == AF_INET6 && + p->addr.v6.s6_addr[0] == 0 && + p->addr.v6.s6_addr[1] == 0 && + p->addr.v6.s6_addr[2] == 0 && + p->addr.v6.s6_addr[3] == 0 && + p->addr.v6.s6_addr[4] == 0 && + p->addr.v6.s6_addr[5] == 0 && + p->addr.v6.s6_addr[6] == 0 && + p->addr.v6.s6_addr[7] == 0 && + p->addr.v6.s6_addr[8] == 0 && + p->addr.v6.s6_addr[9] == 0 && + p->addr.v6.s6_addr[10] == 0xFF && + p->addr.v6.s6_addr[11] == 0xFF); +} + +static int cidr_is6mapped4(lua_State *L) +{ + cidr_t *p = L_checkcidr(L, 1, NULL); + + lua_pushboolean(L, _is_mapped4(p)); + return 1; +} + static int cidr_is6(lua_State *L) { cidr_t *p = L_checkcidr(L, 1, NULL); @@ -546,6 +571,26 @@ static int cidr_broadcast(lua_State *L) return 1; } +static int cidr_mapped4(lua_State *L) +{ + cidr_t *p1 = L_checkcidr(L, 1, NULL); + cidr_t *p2; + + if (!_is_mapped4(p1)) + return 0; + + if (!(p2 = lua_newuserdata(L, sizeof(*p2)))) + return 0; + + p2->family = AF_INET; + p2->bits = (p1->bits > 32) ? 32 : p1->bits; + memcpy(&p2->addr.v4, p1->addr.v6.s6_addr + 12, sizeof(p2->addr.v4)); + + luaL_getmetatable(L, LUCI_IP_CIDR); + lua_setmetatable(L, -2); + return 1; +} + static int cidr_contains(lua_State *L) { cidr_t *p1 = L_checkcidr(L, 1, NULL); @@ -582,7 +627,7 @@ static int _cidr_add_sub(lua_State *L, bool add) { if (p1->family == AF_INET6) { - for (i = 0, carry = 0; i < sizeof(r); i++) + for (i = 0, carry = 0; i < sizeof(r.addr.v6.s6_addr); i++) { if (add) { @@ -869,7 +914,7 @@ static int cb_dump_route(struct nl_msg *msg, void *arg) if (s->callback) lua_call(s->L, 1, 0); else if (hdr->nlmsg_flags & NLM_F_MULTI) - lua_rawseti(s->L, 3, s->index); + lua_rawseti(s->L, -2, s->index); out: s->pending = !!(hdr->nlmsg_flags & NLM_F_MULTI); @@ -961,7 +1006,7 @@ static int _route_dump(lua_State *L, struct dump_filter *filter) out: nl_cb_put(cb); - return (s.index > 0 && s.callback == 0); + return (s.callback == 0); } static int route_get(lua_State *L) @@ -1028,27 +1073,49 @@ static int route_dump(lua_State *L) } +static bool diff_macaddr(struct ether_addr *mac1, struct ether_addr *mac2) +{ + struct ether_addr empty = { }; + + if (!memcmp(mac2, &empty, sizeof(empty))) + return false; + + if (!mac1 || memcmp(mac1, mac2, sizeof(empty))) + return true; + + return false; +} + static int cb_dump_neigh(struct nl_msg *msg, void *arg) { char buf[32]; - struct ether_addr *addr; + struct ether_addr *mac; + struct in6_addr *dst; struct dump_state *s = arg; struct dump_filter *f = s->filter; struct nlmsghdr *hdr = nlmsg_hdr(msg); struct ndmsg *nd = NLMSG_DATA(hdr); struct nlattr *tb[NDA_MAX+1]; + int bitlen; if (hdr->nlmsg_type != RTM_NEWNEIGH || (nd->ndm_family != AF_INET && nd->ndm_family != AF_INET6)) return NL_SKIP; + nlmsg_parse(hdr, sizeof(*nd), tb, NDA_MAX, NULL); + + mac = tb[NDA_LLADDR] ? RTA_DATA(tb[NDA_LLADDR]) : NULL; + dst = tb[NDA_DST] ? RTA_DATA(tb[NDA_DST]) : NULL; + + bitlen = (nd->ndm_family == AF_INET) ? 32 : 128; + if ((f->family && nd->ndm_family != f->family) || (f->iif && nd->ndm_ifindex != f->iif) || - (f->type && !(f->type & nd->ndm_state))) + (f->type && !(f->type & nd->ndm_state)) || + diff_prefix(nd->ndm_family, dst, bitlen, &f->dst) || + diff_macaddr(mac, &f->mac)) goto out; - nlmsg_parse(hdr, sizeof(*nd), tb, NDA_MAX, NULL); - if (s->callback) lua_pushvalue(s->L, 2); @@ -1069,16 +1136,15 @@ static int cb_dump_neigh(struct nl_msg *msg, void *arg) L_setbool(s->L, "noarp", (nd->ndm_state & NUD_NOARP)); L_setbool(s->L, "permanent", (nd->ndm_state & NUD_PERMANENT)); - if (tb[NDA_DST]) - L_setaddr(s->L, "dest", nd->ndm_family, RTA_DATA(tb[NDA_DST]), -1); + if (dst) + L_setaddr(s->L, "dest", nd->ndm_family, dst, -1); - if (tb[NDA_LLADDR]) + if (mac) { - addr = RTA_DATA(tb[NDA_LLADDR]); snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x", - addr->ether_addr_octet[0], addr->ether_addr_octet[1], - addr->ether_addr_octet[2], addr->ether_addr_octet[3], - addr->ether_addr_octet[4], addr->ether_addr_octet[5]); + mac->ether_addr_octet[0], mac->ether_addr_octet[1], + mac->ether_addr_octet[2], mac->ether_addr_octet[3], + mac->ether_addr_octet[4], mac->ether_addr_octet[5]); lua_pushstring(s->L, buf); lua_setfield(s->L, -2, "mac"); @@ -1098,10 +1164,10 @@ out: static int neighbor_dump(lua_State *L) { + cidr_t p = { }; const char *s; - struct dump_filter filter = { - .type = 0xFF & ~NUD_NOARP - }; + struct ether_addr *mac; + struct dump_filter filter = { .type = 0xFF & ~NUD_NOARP }; struct dump_state st = { .callback = lua_isfunction(L, 2), .pending = 1, @@ -1122,6 +1188,13 @@ static int neighbor_dump(lua_State *L) if ((s = L_getstr(L, 1, "dev")) != NULL) filter.iif = if_nametoindex(s); + + if ((s = L_getstr(L, 1, "dest")) != NULL && parse_cidr(s, &p)) + filter.dst = p; + + if ((s = L_getstr(L, 1, "mac")) != NULL && + (mac = ether_aton(s)) != NULL) + filter.mac = *mac; } if (!sock) @@ -1162,7 +1235,97 @@ static int neighbor_dump(lua_State *L) out: nl_cb_put(cb); - return (st.index > 0 && st.callback == 0); + return (st.callback == 0); +} + + +static int cb_dump_link(struct nl_msg *msg, void *arg) +{ + char *p, *addr, buf[48]; + struct dump_state *s = arg; + struct nlmsghdr *hdr = nlmsg_hdr(msg); + struct ifinfomsg *ifm = NLMSG_DATA(hdr); + struct nlattr *tb[IFLA_MAX+1]; + int i, len; + + if (hdr->nlmsg_type != RTM_NEWLINK) + return NL_SKIP; + + nlmsg_parse(hdr, sizeof(*ifm), tb, IFLA_MAX, NULL); + + L_setbool(s->L, "up", (ifm->ifi_flags & IFF_RUNNING)); + L_setint(s->L, "type", ifm->ifi_type); + L_setstr(s->L, "name", if_indextoname(ifm->ifi_index, buf)); + + if (tb[IFLA_MTU]) + L_setint(s->L, "mtu", RTA_U32(tb[IFLA_MTU])); + + if (tb[IFLA_TXQLEN]) + L_setint(s->L, "qlen", RTA_U32(tb[IFLA_TXQLEN])); + + if (tb[IFLA_MASTER]) + L_setdev(s->L, "master", tb[IFLA_MASTER]); + + if (tb[IFLA_ADDRESS]) + { + len = nla_len(tb[IFLA_ADDRESS]); + addr = nla_get_string(tb[IFLA_ADDRESS]); + + if ((len * 3) <= sizeof(buf)) + { + for (p = buf, i = 0; i < len; i++) + p += sprintf(p, "%s%02x", (i ? ":" : ""), (uint8_t)*addr++); + + L_setstr(s->L, "mac", buf); + } + } + + s->pending = 0; + return NL_SKIP; +} + +static int link_get(lua_State *L) +{ + const char *dev = luaL_checkstring(L, 1); + struct dump_state st = { + .pending = 1, + .L = L + }; + + if (!sock) + { + sock = nl_socket_alloc(); + if (!sock) + return _error(L, -1, "Out of memory"); + + if (nl_connect(sock, NETLINK_ROUTE)) + return _error(L, 0, NULL); + } + + struct nl_msg *msg = nlmsg_alloc_simple(RTM_GETLINK, NLM_F_REQUEST); + struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT); + struct ifinfomsg ifm = { .ifi_index = if_nametoindex(dev) }; + + if (!msg || !cb) + return 0; + + nlmsg_append(msg, &ifm, sizeof(ifm), 0); + + nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, cb_dump_link, &st); + nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_done, &st); + nl_cb_err(cb, NL_CB_CUSTOM, cb_error, &st); + + lua_newtable(L); + + nl_send_auto_complete(sock, msg); + + while (st.pending > 0) + nl_recvmsgs(sock, cb); + + nlmsg_free(msg); + nl_cb_put(cb); + + return 1; } @@ -1176,6 +1339,8 @@ static const luaL_reg ip_methods[] = { { "neighbors", neighbor_dump }, + { "link", link_get }, + { } }; @@ -1185,6 +1350,7 @@ static const luaL_reg ip_cidr_methods[] = { { "is4linklocal", cidr_is4linklocal }, { "is6", cidr_is6 }, { "is6linklocal", cidr_is6linklocal }, + { "is6mapped4", cidr_is6mapped4 }, { "lower", cidr_lower }, { "higher", cidr_higher }, { "equal", cidr_equal }, @@ -1193,6 +1359,7 @@ static const luaL_reg ip_cidr_methods[] = { { "host", cidr_host }, { "mask", cidr_mask }, { "broadcast", cidr_broadcast }, + { "mapped4", cidr_mapped4 }, { "contains", cidr_contains }, { "add", cidr_add }, { "sub", cidr_sub },