From 96fdf07acf78ecfc9be76a8b0591f38fe6f1a875 Mon Sep 17 00:00:00 2001
From: Steven Barth <steven@midlink.org>
Date: Sat, 9 Nov 2013 12:01:42 +0100
Subject: [PATCH] Add interface resolving

---
 src/if.c        | 113 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/if.h        |  27 ++++++++++++++
 src/luasocket.c |   2 +
 src/makefile    |   2 +
 src/options.c   |   9 +++++
 5 files changed, 153 insertions(+)
 create mode 100644 src/if.c
 create mode 100644 src/if.h

--- /dev/null
+++ b/src/if.c
@@ -0,0 +1,117 @@
+/*
+ * $Id: if.c $
+ *
+ * Author: Markus Stenberg <fingon@iki.fi>
+ *
+ * Copyright (c) 2012 cisco Systems, Inc.
+ *
+ * Created:       Tue Dec  4 14:50:34 2012 mstenber
+ * Last modified: Wed Dec  5 18:51:08 2012 mstenber
+ * Edit time:     24 min
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+
+#include "if.h"
+
+#include "lauxlib.h"
+
+static int if_global_indextoname(lua_State *L);
+static int if_global_nametoindex(lua_State *L);
+static int if_global_nameindex(lua_State *L);
+
+static luaL_Reg func[] = {
+    { "indextoname", if_global_indextoname},
+    { "nametoindex", if_global_nametoindex},
+    { "nameindex", if_global_nameindex},
+    { NULL, NULL}
+};
+
+int if_open(lua_State *L)
+{
+    lua_pushstring(L, "iface");
+    lua_newtable(L);
+#if LUA_VERSION_NUM < 503
+    luaL_openlib(L, NULL, func, 0);
+#else
+    luaL_setfuncs(L, func, 0);
+#endif
+    lua_settable(L, -3);
+    return 0;
+}
+
+int if_global_indextoname(lua_State *L)
+{
+  unsigned int ifnumber;
+  const char *name;
+  char buf[IF_NAMESIZE+1];
+
+  if (!lua_isnumber(L, 1))
+    {
+      lua_pushnil(L);
+      lua_pushstring(L, "indextoname expects only number argument");
+      return 2;
+    }
+  ifnumber = lua_tonumber(L, 1);
+  if (!(name = if_indextoname(ifnumber, buf)))
+    {
+      lua_pushnil(L);
+      lua_pushstring(L, "nonexistent interface");
+      return 2;
+    }
+  lua_pushstring(L, name);
+  return 1;
+}
+
+int if_global_nametoindex(lua_State *L)
+{
+  unsigned int ifnumber;
+  if (!lua_isstring(L, 1))
+    {
+      lua_pushnil(L);
+      lua_pushstring(L, "nametoindex expects only string argument");
+      return 2;
+    }
+  if (!(ifnumber = if_nametoindex(lua_tostring(L, 1))))
+    {
+      lua_pushnil(L);
+      lua_pushstring(L, "nonexistent interface");
+      return 2;
+    }
+  lua_pushnumber(L, ifnumber);
+  return 1;
+}
+
+int if_global_nameindex(lua_State *L)
+{
+  struct if_nameindex *ni, *oni;
+  int i = 1;
+  oni = ni = if_nameindex();
+  lua_newtable(L);
+  while (ni && ni->if_index && *(ni->if_name))
+    {
+      /* at result[i], we store.. */
+      lua_pushnumber(L, i);
+
+      /* new table with two items - index, name*/
+      lua_newtable(L);
+      lua_pushstring(L, "index");
+      lua_pushnumber(L, ni->if_index);
+      lua_settable(L, -3);
+
+      lua_pushstring(L, "name");
+      lua_pushstring(L, ni->if_name);
+      lua_settable(L, -3);
+
+      /* Then, actually store it */
+      lua_settable(L, -3);
+
+      i++;
+      ni++;
+    }
+  if_freenameindex(oni);
+  return 1;
+}
--- /dev/null
+++ b/src/if.h
@@ -0,0 +1,27 @@
+/*
+ * $Id: if.h $
+ *
+ * Author: Markus Stenberg <fingon@iki.fi>
+ *
+ *  Copyright (c) 2012 cisco Systems, Inc.
+ *
+ * Created:       Tue Dec  4 14:37:24 2012 mstenber
+ * Last modified: Tue Dec  4 14:51:43 2012 mstenber
+ * Edit time:     7 min
+ *
+ */
+
+/* This module provides Lua wrapping for the advanced socket API
+ * defined in RFC3542, or mainly, the access to the system's interface
+ * list. It is necessary for use of recvmsg/sendmsg.
+ *
+ * TODO - Do something clever with Windows?
+ */
+#ifndef IF_H
+#define IF_H
+
+#include "lua.h"
+
+int if_open(lua_State *L);
+
+#endif /* IF_H */
--- a/src/luasocket.c
+++ b/src/luasocket.c
@@ -21,6 +21,7 @@
 #include "tcp.h"
 #include "udp.h"
 #include "select.h"
+#include "if.h"
 
 /*-------------------------------------------------------------------------*\
 * Internal function prototypes
@@ -41,6 +42,7 @@ static const luaL_Reg mod[] = {
     {"tcp", tcp_open},
     {"udp", udp_open},
     {"select", select_open},
+    {"iface", if_open},
     {NULL, NULL}
 };
 
--- a/src/makefile
+++ b/src/makefile
@@ -303,6 +303,7 @@ SOCKET_OBJS= \
 	compat.$(O) \
 	options.$(O) \
 	inet.$(O) \
+	if.$(O) \
 	$(SOCKET) \
 	except.$(O) \
 	select.$(O) \
@@ -440,6 +441,7 @@ auxiliar.$(O): auxiliar.c auxiliar.h
 buffer.$(O): buffer.c buffer.h io.h timeout.h
 except.$(O): except.c except.h
 inet.$(O): inet.c inet.h socket.h io.h timeout.h usocket.h
+if.$(O): if.c if.h
 io.$(O): io.c io.h timeout.h
 luasocket.$(O): luasocket.c luasocket.h auxiliar.h except.h \
 	timeout.h buffer.h io.h inet.h socket.h usocket.h tcp.h \
--- a/src/options.c
+++ b/src/options.c
@@ -7,7 +7,10 @@
 #include "options.h"
 #include "inet.h"
 #include <string.h>
-
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+ 
 /*=========================================================================*\
 * Internal functions prototypes
 \*=========================================================================*/
@@ -414,6 +417,12 @@ static int opt_ip6_setmembership(lua_Sta
     if (!lua_isnil(L, -1)) {
         if (lua_isnumber(L, -1)) {
             val.ipv6mr_interface = (unsigned int) lua_tonumber(L, -1);
+        } else if (lua_isstring(L, -1)) {
+            if (!(val.ipv6mr_interface = if_nametoindex(lua_tostring(L, -1)))) {
+                lua_pushnil(L);
+                lua_pushstring(L, "nonexistent interface");
+                return 2;
+            }
         } else
           luaL_argerror(L, -1, "number 'interface' field expected");
     }
