Page MenuHomeFreeBSD

D25447.id73621.diff
No OneTemporary

D25447.id73621.diff

Index: libexec/flua/Makefile
===================================================================
--- libexec/flua/Makefile
+++ libexec/flua/Makefile
@@ -24,6 +24,10 @@
CFLAGS+= -I${SRCTOP}/lib/liblua -I${.CURDIR}/modules -I${LUASRC}
CFLAGS+= -DLUA_PROGNAME="\"${PROG}\""
+SRCS+= lua_ifconfig.c
+CFLAGS+= -I${SRCTOP}/lib/libifconfig
+LIBADD+= ifconfig sysdecode
+
# readline bits; these aren't needed if we're building a bootstrap flua, as we
# don't expect that one to see any REPL usage.
.if !defined(BOOTSTRAPPING)
Index: libexec/flua/linit_flua.c
===================================================================
--- libexec/flua/linit_flua.c
+++ libexec/flua/linit_flua.c
@@ -36,6 +36,7 @@
#include "lauxlib.h"
#include "lfs.h"
#include "lposix.h"
+#include "lua_ifconfig.h"
#include "lua_ucl.h"
/*
@@ -57,6 +58,7 @@
{LUA_BITLIBNAME, luaopen_bit32},
#endif
/* FreeBSD Extensions */
+ {"ifconfig", luaopen_ifconfig},
{"lfs", luaopen_lfs},
{"posix.sys.stat", luaopen_posix_sys_stat},
{"posix.unistd", luaopen_posix_unistd},
Index: libexec/flua/modules/lua_ifconfig.h
===================================================================
--- libexec/flua/modules/lua_ifconfig.h
+++ libexec/flua/modules/lua_ifconfig.h
@@ -0,0 +1,10 @@
+/*-
+ * This file is in the public domain.
+ */
+/* $FreeBSD$ */
+
+#pragma once
+
+#include <lua.h>
+
+int luaopen_ifconfig(lua_State *L);
Index: libexec/flua/modules/lua_ifconfig.c
===================================================================
--- libexec/flua/modules/lua_ifconfig.c
+++ libexec/flua/modules/lua_ifconfig.c
@@ -0,0 +1,1462 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 2020, Ryan Moeller <freqlabs@FreeBSD.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/* $FreeBSD$ */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <arpa/inet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/ieee8023ad_lacp.h>
+#include <net/if_lagg.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <netinet/in.h>
+#include <netinet/ip_carp.h>
+#include <netinet6/in6_var.h>
+#include <netinet6/nd6.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <ifaddrs.h>
+#include <netdb.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdecode.h>
+#include <sysexits.h>
+
+#include <libifconfig.h>
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+
+#define IFCONFIG_HANDLE_META "ifconfig_handle_t"
+#define STRUCT_IFADDRS_META "struct ifaddrs *"
+
+#define IFFBITS \
+ "\020" \
+ "\001UP" \
+ "\002BROADCAST" \
+ "\003DEBUG" \
+ "\004LOOPBACK" \
+ "\005POINTOPOINT" \
+ "\007RUNNING" \
+ "\010NOARP" \
+ "\011PROMISC" \
+ "\012ALLMULTI" \
+ "\013OACTIVE" \
+ "\014SIMPLEX" \
+ "\015LINK0" \
+ "\016LINK1" \
+ "\017LINK2" \
+ "\020MULTICAST" \
+ "\022PPROMISC" \
+ "\023MONITOR" \
+ "\024STATICARP"
+
+#define IFCAPBITS \
+ "\020" \
+ "\001RXCSUM" \
+ "\002TXCSUM" \
+ "\003NETCONS" \
+ "\004VLAN_MTU" \
+ "\005VLAN_HWTAGGING" \
+ "\006JUMBO_MTU" \
+ "\007POLLING" \
+ "\010VLAN_HWCSUM" \
+ "\011TSO4" \
+ "\012TSO6" \
+ "\013LRO" \
+ "\014WOL_UCAST" \
+ "\015WOL_MCAST" \
+ "\016WOL_MAGIC" \
+ "\017TOE4" \
+ "\020TOE6" \
+ "\021VLAN_HWFILTER" \
+ "\023VLAN_HWTSO" \
+ "\024LINKSTATE" \
+ "\025NETMAP" \
+ "\026RXCSUM_IPV6" \
+ "\027TXCSUM_IPV6" \
+ "\031TXRTLMT" \
+ "\032HWRXTSTMP" \
+ "\033NOMAP" \
+ "\034TXTLS4" \
+ "\035TXTLS6"
+
+#define IN6BITS \
+ "\020" \
+ "\001anycast" \
+ "\002tenative" \
+ "\003duplicated" \
+ "\004detached" \
+ "\005deprecated" \
+ "\007nodad" \
+ "\010autoconf" \
+ "\011temporary" \
+ "\012prefer_source"
+
+#define ND6BITS \
+ "\020" \
+ "\001nud" \
+ "\002accept_rtadv" \
+ "\003prefer_source" \
+ "\004ifdisabled" \
+ "\005dont_set_ifroute" \
+ "\006auto_linklocal" \
+ "\007no_radr" \
+ "\010no_prefer_iface" \
+ "\011no_dad" \
+ "\012ipv6_only" \
+ "\013ipv6_only"
+
+#define LAGGHASHBITS \
+ "\020" \
+ "\001l2" \
+ "\002l3" \
+ "\003l4"
+
+static const char *carp_states[] = { CARP_STATES };
+static const struct lagg_protos lagg_protos[] = LAGG_PROTOS;
+
+/*
+ * Create an array of the set flags in v, using the kernel %b format bits.
+ */
+static void
+push_flags_array(lua_State *L, unsigned v, const char *bits)
+{
+ int i, len;
+
+ lua_newtable(L);
+
+ /* Skip numeric format. */
+ ++bits;
+
+ while ((i = *bits++) != '\0') {
+ if ((v & (1 << (i - 1))) != 0) {
+ for (len = 0; bits[len] > 32; ++len);
+ lua_pushlstring(L, bits, len);
+ lua_rawseti(L, -2, i);
+ bits += len;
+ } else {
+ for (; *bits > 32; ++bits);
+ }
+ }
+}
+
+/*
+ * Decode an array of the flags to set and return as an int.
+ */
+static int
+pop_flags_array(lua_State *L, int index, const char *bits)
+{
+ int v = 0;
+
+ /* Skip numeric format. */
+ ++bits;
+
+ lua_pushnil(L); /* first key */
+ while (lua_next(L, index) != 0) {
+ const char *flag, *flags = bits;
+ int i, len;
+
+ luaL_checkstring(L, index + 2);
+
+ flag = lua_tostring(L, index + 2);
+ lua_pop(L, 1);
+ while ((i = *flags++) != '\0') {
+ for (len = 0; flags[len] > 32; ++len);
+ if (strncmp(flag, flags, len) == 0) {
+ v |= 1 << (i - 1);
+ break;
+ }
+ flags += len;
+ }
+ }
+
+ return (v);
+}
+
+/*
+ * Push a table describing media information.
+ */
+static void
+push_media_info(lua_State *L, int ifmw)
+{
+ char opts[80];
+ int index;
+
+ lua_newtable(L);
+ index = lua_gettop(L);
+
+ lua_pushstring(L, ifconfig_media_get_type(ifmw));
+ lua_setfield(L, index, "type");
+
+ lua_pushstring(L, ifconfig_media_get_subtype(ifmw));
+ lua_setfield(L, index, "subtype");
+
+ ifconfig_media_get_options_string(ifmw, opts, sizeof opts);
+ lua_pushstring(L, opts);
+ lua_setfield(L, index, "options");
+}
+
+/*
+ * Push a table describing an AF_INET address or nil if error.
+ */
+static void
+push_inet4_addrinfo(lua_State *L, ifconfig_handle_t *h, struct ifaddrs *ifa)
+{
+ char addr_buf[NI_MAXHOST];
+ struct ifconfig_inet_addr addr;
+ int index;
+
+ if (ifconfig_inet_get_addrinfo(h, ifa->ifa_name, ifa, &addr) != 0) {
+ lua_pushnil(L);
+ return;
+ }
+
+ lua_newtable(L);
+ index = lua_gettop(L);
+
+ /* TODO: can this just be inet_ntoa? */
+ inet_ntop(AF_INET, &addr.sin->sin_addr, addr_buf, sizeof addr_buf);
+ lua_pushstring(L, addr_buf);
+ lua_setfield(L, index, "inet");
+
+ if (addr.dst != NULL) {
+ lua_pushstring(L, inet_ntoa_r(addr.dst->sin_addr, addr_buf,
+ sizeof addr_buf));
+ lua_setfield(L, index, "destination");
+ }
+
+ lua_pushstring(L, inet_ntoa_r(addr.netmask->sin_addr, addr_buf,
+ sizeof addr_buf));
+ lua_setfield(L, index, "netmask");
+
+ if (addr.broadcast != NULL) {
+ lua_pushstring(L, inet_ntoa_r(addr.broadcast->sin_addr,
+ addr_buf, sizeof addr_buf));
+ lua_setfield(L, index, "broadcast");
+ }
+
+ if (addr.vhid != 0) {
+ lua_pushinteger(L, addr.vhid);
+ lua_setfield(L, index, "vhid");
+ }
+}
+
+/*
+ * Push a table describing an AF_INET6 address or nil if error.
+ */
+static void
+push_inet6_addrinfo(lua_State *L, ifconfig_handle_t *h, struct ifaddrs *ifa)
+{
+ char addr_buf[NI_MAXHOST];
+ struct ifconfig_inet6_addr addr;
+ struct timespec now;
+ int index;
+
+ if (ifconfig_inet6_get_addrinfo(h, ifa->ifa_name, ifa, &addr) != 0) {
+ lua_pushnil(L);
+ return;
+ }
+
+ lua_newtable(L);
+ index = lua_gettop(L);
+
+ if (getnameinfo((struct sockaddr *)addr.sin6, addr.sin6->sin6_len,
+ addr_buf, sizeof addr_buf, NULL, 0, NI_NUMERICHOST) != 0)
+ /* TODO: can this just be inet_ntoa? */
+ inet_ntop(AF_INET6, &addr.sin6->sin6_addr, addr_buf,
+ sizeof addr_buf);
+ lua_pushstring(L, addr_buf);
+ lua_setfield(L, index, "inet6");
+
+ if (addr.dstin6 != NULL) {
+ inet_ntop(AF_INET6, addr.dstin6, addr_buf, sizeof addr_buf);
+ lua_pushstring(L, addr_buf);
+ lua_setfield(L, index, "destination");
+ }
+
+ lua_pushinteger(L, addr.prefixlen);
+ lua_setfield(L, index, "prefixlen");
+
+ if (addr.sin6->sin6_scope_id != 0) {
+ lua_pushinteger(L, addr.sin6->sin6_scope_id);
+ lua_setfield(L, index, "scopeid");
+ }
+
+ push_flags_array(L, addr.flags, IN6BITS);
+ lua_setfield(L, index, "flags");
+
+ clock_gettime(CLOCK_MONOTONIC_FAST, &now);
+ if (addr.lifetime.ia6t_preferred || addr.lifetime.ia6t_expire) {
+ lua_pushinteger(L, MAX(0l,
+ addr.lifetime.ia6t_preferred - now.tv_sec));
+ lua_setfield(L, index, "preferred_lifetime");
+
+ lua_pushinteger(L, MAX(0l,
+ addr.lifetime.ia6t_expire - now.tv_sec));
+ lua_setfield(L, index, "valid_lifetime");
+ }
+
+ if (addr.vhid != 0) {
+ lua_pushinteger(L, addr.vhid);
+ lua_setfield(L, index, "vhid");
+ }
+}
+
+/*
+ * Push a table describing an AF_LINK address or nil if error.
+ */
+static void
+push_link_addrinfo(lua_State *L, ifconfig_handle_t *h, struct ifaddrs *ifa)
+{
+ char addr_buf[NI_MAXHOST];
+ struct sockaddr_dl *sdl;
+ int index, n;
+
+ sdl = (struct sockaddr_dl *)ifa->ifa_addr;
+ if (sdl == NULL || sdl->sdl_alen <= 0) {
+ lua_pushnil(L);
+ return;
+ }
+
+ lua_newtable(L);
+ index = lua_gettop(L);
+
+ switch (sdl->sdl_type) {
+ case IFT_ETHER:
+ case IFT_L2VLAN:
+ case IFT_BRIDGE:
+ if (sdl->sdl_alen != ETHER_ADDR_LEN)
+ break;
+ ether_ntoa_r((struct ether_addr *)LLADDR(sdl), addr_buf);
+ lua_pushstring(L, addr_buf);
+ lua_setfield(L, index, "ether");
+ break;
+ default:
+ n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
+ lua_pushstring(L, link_ntoa(sdl) + n); /* FIXME: link_ntoa_r */
+ lua_setfield(L, index, "lladdr");
+ break;
+ }
+}
+
+/*
+ * Push a table describing an AF_LOCAL address.
+ */
+static void
+push_local_addrinfo(lua_State *L, ifconfig_handle_t *h, struct ifaddrs *ifa)
+{
+ struct sockaddr_un *sun;
+ int index;
+
+ lua_newtable(L);
+ index = lua_gettop(L);
+
+ if (strlen(sun->sun_path) == 0)
+ lua_pushstring(L, "-");
+ else
+ lua_pushstring(L, sun->sun_path);
+ lua_setfield(L, index, "path");
+}
+
+/*
+ * Check the stack for an ifconfig handle userdata at the given index.
+ */
+static ifconfig_handle_t *
+l_ifconfig_checkhandle(lua_State *L, int index)
+{
+ ifconfig_handle_t *h, **hp;
+
+ hp = luaL_checkudata(L, index, IFCONFIG_HANDLE_META);
+ assert(hp != NULL);
+ h = *hp;
+ luaL_argcheck(L, h != NULL, index, "invalid ifconfig handle");
+ return (h);
+}
+
+/*
+ * Check the stack for an ifaddrs userdata at the given index.
+ */
+static struct ifaddrs *
+l_ifconfig_checkifaddrs(lua_State *L, int index)
+{
+ struct ifaddrs *ifa, **ifap;
+
+ ifap = luaL_checkudata(L, index, STRUCT_IFADDRS_META);
+ assert(ifap != NULL);
+ ifa = *ifap;
+ luaL_argcheck(L, ifa != NULL, index, "invalid ifaddr");
+ return (ifa);
+}
+
+/*
+ * Invoke a callback function on the stack with the handle and accumulator
+ * from the stack and the given ifaddrs, leaving the handle, callback, and
+ * accumulator result on the stack after the call.
+ *
+ * This is used by the ifconfig_foreach_* functions to invoke a lua callback.
+ */
+static void
+foreach_cb(ifconfig_handle_t *h, struct ifaddrs *ifa, void *udata)
+{
+ lua_State *L = udata;
+ struct ifaddrs **ifap;
+
+ /* Stack: h,cb,acc */
+
+ /* Make copies of the callback and handle positioned for the call. */
+ lua_pushvalue(L, 1); /* -> h,cb,acc,h */
+ lua_pushvalue(L, 2); /* -> h,cb,acc,h,cb */
+ lua_insert(L, 3); /* -> h,cb,cb,acc,h */
+ lua_insert(L, 4); /* -> h,cb,cb,h,acc */
+
+ /* Push the ifa userdata. */
+ ifap = lua_newuserdata(L, sizeof ifa); /* -> h,cb,cb,h,acc,ifa */
+ assert(ifap != NULL);
+ *ifap = ifa;
+ luaL_getmetatable(L, STRUCT_IFADDRS_META);
+ lua_setmetatable(L, -2);
+
+ /* Reposition the accumulator to be last so it can be optional. */
+ lua_insert(L, 5); /* -> h,cb,cb,h,ifa,acc */
+
+ /* Invoke the callback. */
+ lua_call(L, 3, 1); /* -> h,cb,acc */
+}
+
+/** Explicit close method
+ */
+static int
+l_ifconfig_handle_close(lua_State *L)
+{
+ ifconfig_handle_t *h, **hp;
+
+ hp = luaL_checkudata(L, 1, IFCONFIG_HANDLE_META);
+ assert(hp != NULL);
+ h = *hp;
+ if (h != NULL) {
+ ifconfig_close(h);
+ *hp = NULL;
+ }
+ return (0);
+}
+
+/** Get error info
+ * @return errtype, errno, ioctlname?
+ */
+static int
+l_ifconfig_handle_error(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ ifconfig_errtype errtype;
+
+ h = l_ifconfig_checkhandle(L, 1);
+
+ errtype = ifconfig_err_errtype(h);
+ switch (errtype) {
+ case OK:
+ lua_pushnil(L);
+ return (1);
+ case OTHER:
+ lua_pushstring(L, "OTHER");
+ break;
+ case IOCTL:
+ lua_pushstring(L, "IOCTL");
+ break;
+ case SOCKET:
+ lua_pushstring(L, "SOCKET");
+ break;
+ default:
+ lua_pushstring(L, "<unknown>");
+ break;
+ }
+
+ lua_pushinteger(L, ifconfig_err_errno(h));
+
+ if (errtype == IOCTL) {
+ unsigned long req = ifconfig_err_ioctlreq(h);
+ lua_pushstring(L, sysdecode_ioctlname(req));
+ return (3);
+ }
+
+ return (2);
+}
+
+/** Higher-order fold iterator over interfaces
+ * @param cb A callback function (handle, iface, udata) -> udata
+ * @param udata An initial accumulator value (may be nil)
+ * @return The final accumulator value returned by cb
+ */
+static int
+l_ifconfig_foreach_iface(lua_State *L)
+{
+ const int MAXARGS = 3;
+ ifconfig_handle_t *h;
+ int n;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+
+ /* Ensure the correct number of args. Extras are discarded. */
+ n = lua_gettop(L);
+ if (n == (MAXARGS - 1))
+ lua_pushnil(L);
+ else if (n > MAXARGS)
+ lua_pop(L, n - MAXARGS);
+
+ if (ifconfig_foreach_iface(h, foreach_cb, L) != 0)
+ return luaL_error(L, "iteration failed");
+
+ return (1);
+}
+
+/** Higher-order fold iterator over interface addresses
+ * @param ifa A STRUCT_IFADDRS_META userdata value from foreach_iface
+ * @param cb A callback function (handle, iface, udata) -> udata
+ * @param udata An initial accumulator value (may be nil)
+ * @return The final accumulator value returned by cb
+ */
+static int
+l_ifconfig_foreach_ifaddr(lua_State *L)
+{
+ const int MAXARGS = 4;
+ ifconfig_handle_t *h;
+ struct ifaddrs *ifa;
+ int n;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ ifa = l_ifconfig_checkifaddrs(L, 2);
+ luaL_checktype(L, 3, LUA_TFUNCTION);
+
+ /* Ensure the correct number of args. Extras are discarded. */
+ n = lua_gettop(L);
+ if (n == (MAXARGS - 1))
+ lua_pushnil(L);
+ else if (n > MAXARGS)
+ lua_pop(L, n - MAXARGS);
+ lua_remove(L, 2);
+
+ ifconfig_foreach_ifaddr(h, ifa, foreach_cb, L);
+
+ return (1);
+}
+
+/** Get interface description
+ * @param name The name of an interface
+ * @return Description string if set, otherwise nil
+ */
+static int
+l_ifconfig_get_description(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ char *desc;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_description(h, name, &desc) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, desc);
+
+ return (1);
+}
+
+/** Set interface description
+ * @param name The name of an interface
+ * @param desc Description string to set
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_description(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name, *desc;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkstring(L, 3);
+
+ name = lua_tostring(L, 2);
+ desc = lua_tostring(L, 3);
+ if (ifconfig_set_description(h, name, desc) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Unset interface description
+ * @param name The name of an interface
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_unset_description(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_unset_description(h, name) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Set interface name
+ * @param name The name of an interface
+ * @param newname A new name for the interface
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_name(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name, *newname;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkstring(L, 3);
+
+ name = lua_tostring(L, 2);
+ newname = lua_tostring(L, 3);
+ if (ifconfig_set_name(h, name, newname) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Get original interface name
+ * @param name The name of an interface
+ * @return Original interface name or nil if error
+ */
+static int
+l_ifconfig_get_orig_name(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ char *orig_name;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_orig_name(h, name, &orig_name) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, orig_name);
+
+ return (1);
+}
+
+#if 0 /* setfib not implemented in libifconfig? */
+/** Set interface fib
+ * @param name The name of an interface
+ * @param fib A fib number to use
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_fib(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ ptrdiff_t fib;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkinteger(L, 3);
+
+ name = lua_tostring(L, 2);
+ fib = lua_tointeger(L, 3);
+ luaL_argcheck(L, INT_MAX < fib || fib < INT_MIN, 3, "fib out of range");
+ if (ifconfig_set_fib(h, name, fib) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+#endif
+
+/** Get interface fib
+ * @param name The name of an interface
+ * @return fib of the interface or nil if error
+ */
+static int
+l_ifconfig_get_fib(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ int fib;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_fib(h, name, &fib) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, fib);
+
+ return (1);
+}
+
+/** Set interface mtu
+ * @param name The name of an interface
+ * @param mtu A mtu to use
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_mtu(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ ptrdiff_t mtu;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkinteger(L, 3);
+
+ name = lua_tostring(L, 2);
+ mtu = lua_tointeger(L, 3);
+ luaL_argcheck(L, INT_MIN <= mtu && mtu <= INT_MAX, 3, "mtu out of range");
+ if (ifconfig_set_mtu(h, name, mtu) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Get interface mtu
+ * @param name The name of an interface
+ * @return mtu of the interface or nil if error
+ */
+static int
+l_ifconfig_get_mtu(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ int mtu;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_mtu(h, name, &mtu) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, mtu);
+
+ return (1);
+}
+
+/** Get interface nd6 info
+ * @param name The name of an interface
+ * @return An list of the enabled nd6 options or nil if error
+ */
+static int
+l_ifconfig_get_nd6(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct in6_ndireq nd;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_nd6(h, name, &nd) != 0)
+ lua_pushnil(L);
+ else
+ push_flags_array(L, nd.ndi.flags, ND6BITS);
+
+ return (1);
+}
+
+/** Set interface metric
+ * @param name The name of an interface
+ * @param metric A metric to use
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_metric(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ ptrdiff_t metric;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkinteger(L, 3);
+
+ name = lua_tostring(L, 2);
+ metric = lua_tointeger(L, 3);
+ luaL_argcheck(L, INT_MAX < metric || metric < INT_MIN, 3,
+ "metric out of range");
+ if (ifconfig_set_metric(h, name, metric) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Get interface metric
+ * @param name The name of an interface
+ * @return metric of the interface or nil if error
+ */
+static int
+l_ifconfig_get_metric(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ int metric;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_metric(h, name, &metric) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushinteger(L, metric);
+
+ return (1);
+}
+
+/** Set interface capabilities
+ * @param name The name of an interface
+ * @param caps An array of the capabilities to be enabled on the interface
+ * (capabilities not listed will be disabled)
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_capability(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ int capability;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checktype(L, 3, LUA_TTABLE);
+
+ name = lua_tostring(L, 2);
+ capability = pop_flags_array(L, 3, IFCAPBITS);
+ if (ifconfig_set_capability(h, name, capability) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Get interface capabilities
+ * @param name The name of an interface
+ * @return A table of the enabled/supported capabilites or nil if error
+ */
+static int
+l_ifconfig_get_capability(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifconfig_capabilities capability;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_capability(h, name, &capability) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ lua_pushstring(L, "options");
+ push_flags_array(L, capability.curcap, IFCAPBITS);
+ lua_rawset(L, 3);
+
+ lua_pushstring(L, "capabilities");
+ push_flags_array(L, capability.reqcap, IFCAPBITS);
+ lua_rawset(L, 3);
+
+ return (1);
+}
+
+/** Get interface groups list
+ * @param name The name of an interface
+ * @return A table of the groups containing the interface or nil if error
+ */
+static int
+l_ifconfig_get_groups(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifgroupreq ifgr;
+ struct ifg_req *ifg;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_groups(h, name, &ifgr) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ for (ifg = ifgr.ifgr_groups;
+ ifg != NULL && ifgr.ifgr_len >= sizeof *ifg;
+ ++ifg, ifgr.ifgr_len -= sizeof *ifg) {
+ if (strcmp(ifg->ifgrq_group, "all") == 0)
+ continue;
+ lua_pushstring(L, ifg->ifgrq_group);
+ lua_rawseti(L, 3, lua_rawlen(L, 3) + 1);
+ }
+
+ return (1);
+}
+
+/** Get interface status
+ * @param name The name of an interface
+ * @return Interface status as a string or nil if error
+ */
+static int
+l_ifconfig_get_status(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifstat status;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_get_ifstatus(h, name, &status) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, status.ascii);
+
+ return (1);
+}
+
+/** Get interface media info
+ * @param name The name of an interface
+ * @return A table describing the interface media or nil if error
+ */
+static int
+l_ifconfig_get_media(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifmediareq *ifmr;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_media_get_mediareq(h, name, &ifmr) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ push_media_info(L, ifmr->ifm_current);
+ lua_setfield(L, 3, "current");
+
+ push_media_info(L, ifmr->ifm_active);
+ lua_setfield(L, 3, "active");
+
+ lua_newtable(L);
+ for (size_t i = 0; i < ifmr->ifm_count; ++i) {
+ push_media_info(L, ifmr->ifm_ulist[i]);
+ lua_rawseti(L, 4, lua_rawlen(L, 4) + 1);
+ }
+ lua_setfield(L, 3, "supported");
+
+ lua_pushstring(L, ifconfig_media_get_status(ifmr));
+ lua_setfield(L, 3, "status");
+
+ free(ifmr);
+
+ return (1);
+}
+
+/** Get interface carp info
+ * @param name
+ * @return A table describing the interface carp vhids or nil if error
+ */
+static int
+l_ifconfig_get_carp(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct carpreq carpr[CARP_MAXVHID];
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_carp_get_info(h, name, carpr, nitems(carpr)) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+
+ for (size_t i = 0; i < carpr[0].carpr_count; ++i) {
+ lua_newtable(L);
+
+ lua_pushstring(L, carp_states[carpr[i].carpr_state]);
+ lua_setfield(L, 4, "state");
+
+ lua_pushinteger(L, carpr[i].carpr_vhid);
+ lua_setfield(L, 4, "vhid");
+
+ lua_pushinteger(L, carpr[i].carpr_advbase);
+ lua_setfield(L, 4, "advbase");
+
+ lua_pushinteger(L, carpr[i].carpr_advskew);
+ lua_setfield(L, 4, "advskew");
+
+ lua_rawseti(L, 3, lua_rawlen(L, 3) + 1);
+ }
+
+ return (1);
+}
+
+/** Get address info
+ * @param addr An ifaddrs userdata object
+ * @return Table describing the address or nil if error
+ */
+static int
+l_ifconfig_addr_info(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ struct ifaddrs *ifa;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ ifa = l_ifconfig_checkifaddrs(L, 2);
+
+ switch (ifa->ifa_addr->sa_family) {
+ case AF_INET:
+ push_inet4_addrinfo(L, h, ifa);
+ break;
+ case AF_INET6:
+ push_inet6_addrinfo(L, h, ifa);
+ break;
+ case AF_LINK:
+ push_link_addrinfo(L, h, ifa);
+ break;
+ case AF_LOCAL:
+ push_local_addrinfo(L, h, ifa);
+ break;
+ case AF_UNSPEC:
+ default:
+ lua_pushnil(L);
+ break;
+ }
+
+ return (1);
+}
+
+/** Get lagg interface status
+ * @param name The name of a lagg interface
+ * @return Table describing the status of the lagg or nil if error
+ */
+static int
+l_ifconfig_get_lagg_status(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct ifconfig_lagg_status *lagg_status;
+ const char *protoname = "<unknown>";
+ int index;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_lagg_get_lagg_status(h, name, &lagg_status) != 0) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ lua_newtable(L);
+ index = lua_gettop(L);
+
+ for (size_t i = 0; i < nitems(lagg_protos); ++i) {
+ if (lagg_status->ra->ra_proto == lagg_protos[i].lpr_proto) {
+ protoname = lagg_protos[i].lpr_name;
+ break;
+ }
+ }
+ lua_pushstring(L, protoname);
+ lua_setfield(L, index, "laggproto");
+
+ push_flags_array(L, lagg_status->rf->rf_flags & LAGG_F_HASHMASK,
+ LAGGHASHBITS);
+ lua_setfield(L, index, "lagghash");
+
+ lua_newtable(L);
+ ++index;
+
+ push_flags_array(L, lagg_status->ro->ro_opts, LAGG_OPT_BITS);
+ lua_setfield(L, index, "flags");
+
+ lua_pushinteger(L, lagg_status->ro->ro_flowid_shift);
+ lua_setfield(L, index, "flowid_shift");
+
+ if (lagg_status->ra->ra_proto == LAGG_PROTO_ROUNDROBIN) {
+ lua_pushinteger(L, lagg_status->ro->ro_bkt);
+ lua_setfield(L, index, "rr_limit");
+ }
+
+ --index;
+ lua_setfield(L, index, "options");
+
+ lua_newtable(L);
+ ++index;
+
+ lua_pushinteger(L, lagg_status->ro->ro_active);
+ lua_setfield(L, index, "active");
+
+ lua_pushinteger(L, lagg_status->ro->ro_flapping);
+ lua_setfield(L, index, "flapping");
+
+ --index;
+ lua_setfield(L, index, "stats");
+
+ lua_newtable(L);
+ ++index;
+
+ for (size_t i = 0; i < lagg_status->ra->ra_ports; ++i) {
+ struct lagg_reqport *lagg_port = &lagg_status->ra->ra_port[i];
+
+ lua_newtable(L);
+ ++index;
+
+ lua_pushstring(L, lagg_port->rp_portname);
+ lua_setfield(L, index, "laggport");
+
+ push_flags_array(L, lagg_port->rp_flags, LAGG_PORT_BITS);
+ lua_setfield(L, index, "flags");
+
+ if (lagg_status->ra->ra_proto == LAGG_PROTO_LACP) {
+ struct lacp_opreq *lacp_port = (struct lacp_opreq *)
+ &lagg_port->rp_lacpreq;
+
+ push_flags_array(L, lacp_port->actor_state,
+ LACP_STATE_BITS);
+ lua_setfield(L, index, "lacp_state");
+ }
+
+ --index;
+ lua_rawseti(L, index, lua_rawlen(L, index) + 1);
+ }
+
+ --index;
+ lua_setfield(L, index, "ports");
+
+ ifconfig_lagg_free_lagg_status(lagg_status);
+
+ return (1);
+}
+
+/** Get the parent laggdev of a laggport interface
+ * @param name The name of a laggport interface
+ * @return Parent laggdev name or nil if error
+ */
+static int
+l_ifconfig_get_laggport_laggdev(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ struct lagg_reqport lagg_port;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_lagg_get_laggport_status(h, name, &lagg_port) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, lagg_port.rp_ifname);
+
+ return (1);
+}
+
+/** Destroy an interface
+ * @param name The name of an interface
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_destroy(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_destroy_interface(h, name) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+/** Create an interface
+ * @param name The name of an interface
+ * @return Created interface name or nil if error
+ */
+static int
+l_ifconfig_create(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name;
+ char *ifname;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+
+ name = lua_tostring(L, 2);
+ if (ifconfig_create_interface(h, name, &ifname) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, ifname);
+
+ return (1);
+}
+
+/** Create a vlan interface
+ * @param name The name of a vlan interface to create
+ * @param vlandev The name of an interface to attach to
+ * @param vlantag A vlan number to use
+ * @return The name of the created interface or nil if error
+ */
+static int
+l_ifconfig_create_vlan(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name, *vlandev;
+ char *ifname;
+ ptrdiff_t vlantag;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkstring(L, 3);
+ luaL_checkinteger(L, 4);
+
+ name = lua_tostring(L, 2);
+ vlandev = lua_tostring(L, 3);
+ vlantag = lua_tointeger(L, 4);
+ luaL_argcheck(L, 0 <= vlantag && vlantag <= UINT16_MAX, 4,
+ "vlantag out of range");
+ if (ifconfig_create_interface_vlan(h, name, &ifname, vlandev, vlantag) != 0)
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, ifname);
+
+ return (1);
+}
+
+/** Set vlandev and vlantag for a vlan interface
+ * @param name The name of a vlan interface
+ * @param vlandev The name of the interface to attach to
+ * @param vlantag A vlan number to use
+ * @return true if success, false if error
+ */
+static int
+l_ifconfig_set_vlantag(lua_State *L)
+{
+ ifconfig_handle_t *h;
+ const char *name, *vlandev;
+ ptrdiff_t vlantag;
+
+ h = l_ifconfig_checkhandle(L, 1);
+ luaL_checkstring(L, 2);
+ luaL_checkstring(L, 3);
+ luaL_checkinteger(L, 4);
+
+ name = lua_tostring(L, 2);
+ vlandev = lua_tostring(L, 3);
+ vlantag = lua_tointeger(L, 4);
+ luaL_argcheck(L, 0 <= vlantag && vlantag <= UINT16_MAX, 4,
+ "vlantag out of range");
+ if (ifconfig_set_vlantag(h, name, vlandev, vlantag) != 0)
+ lua_pushboolean(L, false);
+ else
+ lua_pushboolean(L, true);
+
+ return (1);
+}
+
+static const struct luaL_Reg l_ifconfig_handle[] = {
+ {"close", l_ifconfig_handle_close},
+ {"error", l_ifconfig_handle_error},
+ {"foreach_iface", l_ifconfig_foreach_iface},
+ {"foreach_ifaddr", l_ifconfig_foreach_ifaddr},
+ {"get_description", l_ifconfig_get_description},
+ {"set_description", l_ifconfig_set_description},
+ {"unset_description", l_ifconfig_unset_description},
+ {"set_name", l_ifconfig_set_name},
+ {"get_orig_name", l_ifconfig_get_orig_name},
+#if 0 /* setfib not implemented in libifconfig? */
+ {"set_fib", l_ifconfig_set_fib},
+#endif
+ {"get_fib", l_ifconfig_get_fib},
+ {"set_mtu", l_ifconfig_set_mtu},
+ {"get_mtu", l_ifconfig_get_mtu},
+ {"get_nd6", l_ifconfig_get_nd6},
+ {"set_metric", l_ifconfig_set_metric},
+ {"get_metric", l_ifconfig_get_metric},
+ {"set_capability", l_ifconfig_set_capability},
+ {"get_capability", l_ifconfig_get_capability},
+ {"get_groups", l_ifconfig_get_groups},
+ {"get_status", l_ifconfig_get_status},
+ {"get_media", l_ifconfig_get_media},
+ {"get_carp", l_ifconfig_get_carp},
+ {"addr_info", l_ifconfig_addr_info},
+ {"get_lagg_status", l_ifconfig_get_lagg_status},
+ {"get_laggport_laggdev", l_ifconfig_get_laggport_laggdev},
+ {"destroy", l_ifconfig_destroy},
+ {"create", l_ifconfig_create},
+ {"create_vlan", l_ifconfig_create_vlan},
+ {"set_vlantag", l_ifconfig_set_vlantag},
+ {NULL, NULL}
+};
+
+static void
+l_ifconfig_handle_meta(lua_State *L)
+{
+ luaL_newmetatable(L, IFCONFIG_HANDLE_META);
+
+ /* metatable.__index = metatable */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ /* Automatically close handle when garbage collected. */
+ lua_pushcfunction(L, l_ifconfig_handle_close);
+ lua_setfield(L, -2, "__gc");
+
+ luaL_setfuncs(L, l_ifconfig_handle, 0);
+
+ lua_pop(L, 1);
+}
+
+/** Get interface name
+ * @return Name of the interface as a string
+ */
+static int
+l_struct_ifaddrs_name(lua_State *L)
+{
+ struct ifaddrs *ifa;
+
+ ifa = l_ifconfig_checkifaddrs(L, 1);
+
+ lua_pushstring(L, ifa->ifa_name);
+ return (1);
+}
+
+static const struct luaL_Reg l_struct_ifaddrs[] = {
+ {"name", l_struct_ifaddrs_name},
+ {NULL, NULL}
+};
+
+static void
+l_struct_ifaddrs_meta(lua_State *L)
+{
+ luaL_newmetatable(L, STRUCT_IFADDRS_META);
+
+ /* metatable.__index = metatable */
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+
+ luaL_setfuncs(L, l_struct_ifaddrs, 0);
+
+ lua_pop(L, 1);
+}
+
+static int
+l_ifconfig_open(lua_State *L)
+{
+ ifconfig_handle_t *h, **hp;
+
+ if ((h = ifconfig_open()) == NULL) {
+ lua_pushnil(L);
+ return (1);
+ }
+
+ hp = lua_newuserdata(L, sizeof h);
+ assert(hp != NULL);
+ *hp = h;
+ luaL_getmetatable(L, IFCONFIG_HANDLE_META);
+ lua_setmetatable(L, -2);
+ return (1);
+}
+
+static const struct luaL_Reg l_ifconfig[] = {
+ {"open", l_ifconfig_open},
+ {NULL, NULL}
+};
+
+int
+luaopen_ifconfig(lua_State *L)
+{
+ l_ifconfig_handle_meta(L);
+ l_struct_ifaddrs_meta(L);
+
+ lua_newtable(L);
+ luaL_setfuncs(L, l_ifconfig, 0);
+ return (1);
+}

File Metadata

Mime Type
text/plain
Expires
Wed, Feb 25, 4:33 PM (11 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
28991836
Default Alt Text
D25447.id73621.diff (35 KB)

Event Timeline