Jelajahi Sumber

ncd: add iptables module

ambrop7 15 tahun lalu
induk
melakukan
2b439110e5

+ 1 - 0
blog_channels.txt

@@ -10,6 +10,7 @@ ncd_concat 4
 ncd_net_backend_physical 4
 ncd_net_backend_physical 4
 ncd_net_backend_badvpn 4
 ncd_net_backend_badvpn 4
 ncd_net_dns 4
 ncd_net_dns 4
+ncd_net_iptables 4
 ncd_net_ipv4_addr 4
 ncd_net_ipv4_addr 4
 ncd_net_ipv4_dhcp 4
 ncd_net_ipv4_dhcp 4
 ncd_net_ipv4_route 4
 ncd_net_ipv4_route 4

+ 4 - 0
generated/blog_channel_ncd_net_iptables.h

@@ -0,0 +1,4 @@
+#ifdef BLOG_CURRENT_CHANNEL
+#undef BLOG_CURRENT_CHANNEL
+#endif
+#define BLOG_CURRENT_CHANNEL BLOG_CHANNEL_ncd_net_iptables

+ 21 - 20
generated/blog_channels_defines.h

@@ -10,23 +10,24 @@
 #define BLOG_CHANNEL_ncd_net_backend_physical 9
 #define BLOG_CHANNEL_ncd_net_backend_physical 9
 #define BLOG_CHANNEL_ncd_net_backend_badvpn 10
 #define BLOG_CHANNEL_ncd_net_backend_badvpn 10
 #define BLOG_CHANNEL_ncd_net_dns 11
 #define BLOG_CHANNEL_ncd_net_dns 11
-#define BLOG_CHANNEL_ncd_net_ipv4_addr 12
-#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 13
-#define BLOG_CHANNEL_ncd_net_ipv4_route 14
-#define BLOG_CHANNEL_StreamPeerIO 15
-#define BLOG_CHANNEL_DatagramPeerIO 16
-#define BLOG_CHANNEL_BReactor 17
-#define BLOG_CHANNEL_BSignal 18
-#define BLOG_CHANNEL_FragmentProtoAssembler 19
-#define BLOG_CHANNEL_BPredicate 20
-#define BLOG_CHANNEL_ServerConnection 21
-#define BLOG_CHANNEL_Listener 22
-#define BLOG_CHANNEL_DataProto 23
-#define BLOG_CHANNEL_FrameDecider 24
-#define BLOG_CHANNEL_BSocksClient 25
-#define BLOG_CHANNEL_BDHCPClientCore 26
-#define BLOG_CHANNEL_BDHCPClient 27
-#define BLOG_CHANNEL_NCDIfConfig 28
-#define BLOG_CHANNEL_BUnixSignal 29
-#define BLOG_CHANNEL_BProcess 30
-#define BLOG_NUM_CHANNELS 31
+#define BLOG_CHANNEL_ncd_net_iptables 12
+#define BLOG_CHANNEL_ncd_net_ipv4_addr 13
+#define BLOG_CHANNEL_ncd_net_ipv4_dhcp 14
+#define BLOG_CHANNEL_ncd_net_ipv4_route 15
+#define BLOG_CHANNEL_StreamPeerIO 16
+#define BLOG_CHANNEL_DatagramPeerIO 17
+#define BLOG_CHANNEL_BReactor 18
+#define BLOG_CHANNEL_BSignal 19
+#define BLOG_CHANNEL_FragmentProtoAssembler 20
+#define BLOG_CHANNEL_BPredicate 21
+#define BLOG_CHANNEL_ServerConnection 22
+#define BLOG_CHANNEL_Listener 23
+#define BLOG_CHANNEL_DataProto 24
+#define BLOG_CHANNEL_FrameDecider 25
+#define BLOG_CHANNEL_BSocksClient 26
+#define BLOG_CHANNEL_BDHCPClientCore 27
+#define BLOG_CHANNEL_BDHCPClient 28
+#define BLOG_CHANNEL_NCDIfConfig 29
+#define BLOG_CHANNEL_BUnixSignal 30
+#define BLOG_CHANNEL_BProcess 31
+#define BLOG_NUM_CHANNELS 32

+ 1 - 0
generated/blog_channels_list.h

@@ -10,6 +10,7 @@
 {.name = "ncd_net_backend_physical", .loglevel = 4},
 {.name = "ncd_net_backend_physical", .loglevel = 4},
 {.name = "ncd_net_backend_badvpn", .loglevel = 4},
 {.name = "ncd_net_backend_badvpn", .loglevel = 4},
 {.name = "ncd_net_dns", .loglevel = 4},
 {.name = "ncd_net_dns", .loglevel = 4},
+{.name = "ncd_net_iptables", .loglevel = 4},
 {.name = "ncd_net_ipv4_addr", .loglevel = 4},
 {.name = "ncd_net_ipv4_addr", .loglevel = 4},
 {.name = "ncd_net_ipv4_dhcp", .loglevel = 4},
 {.name = "ncd_net_ipv4_dhcp", .loglevel = 4},
 {.name = "ncd_net_ipv4_route", .loglevel = 4},
 {.name = "ncd_net_ipv4_route", .loglevel = 4},

+ 2 - 0
ncd/CMakeLists.txt

@@ -4,6 +4,7 @@ add_executable(badvpn-ncd
     NCDModule.c
     NCDModule.c
     NCDIfConfig.c
     NCDIfConfig.c
     NCDInterfaceMonitor.c
     NCDInterfaceMonitor.c
+    modules/command_template.c
     modules/var.c
     modules/var.c
     modules/list.c
     modules/list.c
     modules/depend.c
     modules/depend.c
@@ -11,6 +12,7 @@ add_executable(badvpn-ncd
     modules/net_backend_physical.c
     modules/net_backend_physical.c
     modules/net_backend_badvpn.c
     modules/net_backend_badvpn.c
     modules/net_dns.c
     modules/net_dns.c
+    modules/net_iptables.c
     modules/net_ipv4_addr.c
     modules/net_ipv4_addr.c
     modules/net_ipv4_route.c
     modules/net_ipv4_route.c
     modules/net_ipv4_dhcp.c
     modules/net_ipv4_dhcp.c

+ 30 - 0
ncd/NCDValue.c

@@ -241,3 +241,33 @@ int NCDValue_ListRead (NCDValue *o, int num, ...)
     
     
     return 1;
     return 1;
 }
 }
+
+int NCDValue_ListReadHead (NCDValue *o, int num, ...)
+{
+    value_assert(o);
+    ASSERT(o->type == NCDVALUE_LIST)
+    ASSERT(num >= 0)
+    
+    if (num > NCDValue_ListCount(o)) {
+        return 0;
+    }
+    
+    va_list ap;
+    va_start(ap, num);
+    
+    LinkedList2Node *n = LinkedList2_GetFirst(&o->list);
+    while (num > 0) {
+        ASSERT(n)
+        NCDListElement *e = UPPER_OBJECT(n, NCDListElement, list_node);
+        
+        NCDValue **dest = va_arg(ap, NCDValue **);
+        *dest = &e->v;
+        
+        n = LinkedList2Node_Next(n);
+        num--;
+    }
+    
+    va_end(ap);
+    
+    return 1;
+}

+ 1 - 0
ncd/NCDValue.h

@@ -56,5 +56,6 @@ size_t NCDValue_ListCount (NCDValue *o);
 NCDValue * NCDValue_ListFirst (NCDValue *o);
 NCDValue * NCDValue_ListFirst (NCDValue *o);
 NCDValue * NCDValue_ListNext (NCDValue *o, NCDValue *ev);
 NCDValue * NCDValue_ListNext (NCDValue *o, NCDValue *ev);
 int NCDValue_ListRead (NCDValue *o, int num, ...);
 int NCDValue_ListRead (NCDValue *o, int num, ...);
+int NCDValue_ListReadHead (NCDValue *o, int num, ...);
 
 
 #endif
 #endif

+ 199 - 0
ncd/modules/command_template.c

@@ -0,0 +1,199 @@
+/**
+ * @file command_template.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <ncd/modules/command_template.h>
+
+#define STATE_ADDING 1
+#define STATE_ADDING_NEED_DELETE 2
+#define STATE_DONE 3
+#define STATE_DELETING 4
+
+struct instance {
+    NCDModuleInst *i;
+    command_template_build_cmdline build_cmdline;
+    int blog_channel;
+    int state;
+    int have_process;
+    BProcess process;
+};
+
+static int start_process (struct instance *o, int remove);
+static void process_handler (struct instance *o, int normally, uint8_t normally_exit_status);
+
+int start_process (struct instance *o, int remove)
+{
+    // build command line
+    char *exec;
+    CmdLine cl;
+    if (!(o->build_cmdline(o->i, remove, &exec, &cl))) {
+        NCDModuleInst_Backend_Log(o->i, o->blog_channel, BLOG_ERROR, "build_cmdline callback failed");
+        goto fail0;
+    }
+    
+    // start process
+    if (!BProcess_Init(&o->process, o->i->manager, (BProcess_handler)process_handler, o, exec, CmdLine_Get(&cl), NULL)) {
+        NCDModuleInst_Backend_Log(o->i, o->blog_channel, BLOG_ERROR, "BProcess_Init failed");
+        goto fail1;
+    }
+    
+    CmdLine_Free(&cl);
+    free(exec);
+    
+    return 1;
+    
+fail1:
+    CmdLine_Free(&cl);
+    free(exec);
+fail0:
+    return 0;
+}
+
+void process_handler (struct instance *o, int normally, uint8_t normally_exit_status)
+{
+    ASSERT(o->have_process)
+    ASSERT(o->state == STATE_ADDING || o->state == STATE_ADDING_NEED_DELETE || o->state == STATE_DELETING)
+    
+    // free process
+    BProcess_Free(&o->process);
+    
+    // set have no process
+    o->have_process = 0;
+    
+    if (!normally || normally_exit_status != 0) {
+        NCDModuleInst_Backend_Log(o->i, o->blog_channel, BLOG_ERROR, "command failed");
+        
+        NCDModuleInst_Backend_Died(o->i, 1);
+        return;
+    }
+    
+    switch (o->state) {
+        case STATE_ADDING: {
+            o->state = STATE_DONE;
+            
+            // signal up
+            NCDModuleInst_Backend_Event(o->i, NCDMODULE_EVENT_UP);
+        } break;
+        
+        case STATE_ADDING_NEED_DELETE: {
+            // start deleting process
+            if (!start_process(o, 1)) {
+                NCDModuleInst_Backend_Died(o->i, 1);
+                return;
+            }
+            
+            // set have process
+            o->have_process = 1;
+            
+            // set state
+            o->state = STATE_DELETING;
+        } break;
+        
+        case STATE_DELETING: {
+            // finish
+            NCDModuleInst_Backend_Died(o->i, 0);
+            return;
+        } break;
+    }
+}
+
+void * command_template_new (NCDModuleInst *i, command_template_build_cmdline build_cmdline, int blog_channel)
+{
+    // allocate instance
+    struct instance *o = malloc(sizeof(*o));
+    if (!o) {
+        NCDModuleInst_Backend_Log(i, blog_channel, BLOG_ERROR, "failed to allocate instance");
+        goto fail0;
+    }
+    
+    // init arguments
+    o->i = i;
+    o->build_cmdline = build_cmdline;
+    o->blog_channel = blog_channel;
+    
+    // start adding process
+    if (!start_process(o, 0)) {
+        goto fail1;
+    }
+    
+    // set have process
+    o->have_process = 1;
+    
+    // set state
+    o->state = STATE_ADDING;
+    
+    return o;
+    
+fail1:
+    free(o);
+fail0:
+    return NULL;
+}
+
+void command_template_func_free (void *vo)
+{
+    struct instance *o = vo;
+    
+    // free process
+    if (o->have_process) {
+        // kill process
+        BProcess_Kill(&o->process);
+        
+        // free process
+        BProcess_Free(&o->process);
+    }
+    
+    // free instance
+    free(o);
+}
+
+void command_template_func_die (void *vo)
+{
+    struct instance *o = vo;
+    ASSERT(o->state == STATE_ADDING || o->state == STATE_DONE)
+    
+    switch (o->state) {
+        case STATE_ADDING: {
+            ASSERT(o->have_process)
+            
+            o->state = STATE_ADDING_NEED_DELETE;
+        } break;
+        
+        case STATE_DONE: {
+            ASSERT(!o->have_process)
+            
+            // start deleting process
+            if (!start_process(o, 1)) {
+                NCDModuleInst_Backend_Died(o->i, 1);
+                return;
+            }
+            
+            // set have process
+            o->have_process = 1;
+            
+            // set state
+            o->state = STATE_DELETING;
+        } break;
+    }
+}

+ 42 - 0
ncd/modules/command_template.h

@@ -0,0 +1,42 @@
+/**
+ * @file command_template.h
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * @section DESCRIPTION
+ * 
+ * Template for a module which executes a command to start and stop.
+ * The command is executed asynchronously.
+ */
+
+#ifndef BADVPN_NCD_MODULES_COMMAND_TEMPLATE_H
+#define BADVPN_NCD_MODULES_COMMAND_TEMPLATE_H
+
+#include <misc/cmdline.h>
+#include <ncd/NCDModule.h>
+
+#include <generated/blog_channel_ncd_net_iptables.h>
+
+typedef int (*command_template_build_cmdline) (NCDModuleInst *i, int remove, char **exec, CmdLine *cl);
+
+void * command_template_new (NCDModuleInst *i, command_template_build_cmdline build_cmdline, int blog_channel);
+void command_template_func_free (void *vo);
+void command_template_func_die (void *vo);
+
+#endif

+ 2 - 0
ncd/modules/modules.h

@@ -34,6 +34,7 @@ extern const struct NCDModuleGroup ncdmodule_concat;
 extern const struct NCDModuleGroup ncdmodule_net_backend_physical;
 extern const struct NCDModuleGroup ncdmodule_net_backend_physical;
 extern const struct NCDModuleGroup ncdmodule_net_backend_badvpn;
 extern const struct NCDModuleGroup ncdmodule_net_backend_badvpn;
 extern const struct NCDModuleGroup ncdmodule_net_dns;
 extern const struct NCDModuleGroup ncdmodule_net_dns;
+extern const struct NCDModuleGroup ncdmodule_net_iptables;
 extern const struct NCDModuleGroup ncdmodule_net_ipv4_addr;
 extern const struct NCDModuleGroup ncdmodule_net_ipv4_addr;
 extern const struct NCDModuleGroup ncdmodule_net_ipv4_route;
 extern const struct NCDModuleGroup ncdmodule_net_ipv4_route;
 extern const struct NCDModuleGroup ncdmodule_net_ipv4_dhcp;
 extern const struct NCDModuleGroup ncdmodule_net_ipv4_dhcp;
@@ -46,6 +47,7 @@ static const struct NCDModuleGroup *ncd_modules[] = {
     &ncdmodule_net_backend_physical,
     &ncdmodule_net_backend_physical,
     &ncdmodule_net_backend_badvpn,
     &ncdmodule_net_backend_badvpn,
     &ncdmodule_net_dns,
     &ncdmodule_net_dns,
+    &ncdmodule_net_iptables,
     &ncdmodule_net_ipv4_addr,
     &ncdmodule_net_ipv4_addr,
     &ncdmodule_net_ipv4_route,
     &ncdmodule_net_ipv4_route,
     &ncdmodule_net_ipv4_dhcp,
     &ncdmodule_net_ipv4_dhcp,

+ 124 - 0
ncd/modules/net_iptables.c

@@ -0,0 +1,124 @@
+/**
+ * @file net_iptables.c
+ * @author Ambroz Bizjak <ambrop7@gmail.com>
+ * 
+ * @section LICENSE
+ * 
+ * This file is part of BadVPN.
+ * 
+ * BadVPN is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ * 
+ * BadVPN is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ * 
+ * @section DESCRIPTION
+ * 
+ * iptables module.
+ * 
+ * Synopsis: net.iptables.append(string table, string chain, string arg1,  ...)
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <ncd/modules/command_template.h>
+
+#include <generated/blog_channel_ncd_net_iptables.h>
+
+#define ModuleLog(i, ...) NCDModuleInst_Backend_Log((i), BLOG_CURRENT_CHANNEL, __VA_ARGS__)
+
+#define IPTABLES_PATH "/sbin/iptables"
+
+static int build_cmdline (NCDModuleInst *i, int remove, char **exec, CmdLine *cl)
+{
+    // read arguments
+    NCDValue *table_arg;
+    NCDValue *chain_arg;
+    if (!NCDValue_ListReadHead(i->args, 2, &table_arg, &chain_arg)) {
+        ModuleLog(i, BLOG_ERROR, "wrong arity");
+        goto fail0;
+    }
+    if (NCDValue_Type(table_arg) != NCDVALUE_STRING || NCDValue_Type(chain_arg) != NCDVALUE_STRING) {
+        ModuleLog(i, BLOG_ERROR, "wrong type");
+        goto fail0;
+    }
+    char *table = NCDValue_StringValue(table_arg);
+    char *chain = NCDValue_StringValue(chain_arg);
+    
+    // alloc exec
+    if (!(*exec = strdup(IPTABLES_PATH))) {
+        ModuleLog(i, BLOG_ERROR, "strdup failed");
+        goto fail0;
+    }
+    
+    // start cmdline
+    if (!CmdLine_Init(cl)) {
+        ModuleLog(i, BLOG_ERROR, "CmdLine_Init failed");
+        goto fail1;
+    }
+    
+    // add header
+    if (!CmdLine_Append(cl, IPTABLES_PATH) || !CmdLine_Append(cl, "-t") || !CmdLine_Append(cl, table) || !CmdLine_Append(cl, (remove ? "-D" : "-A")) || !CmdLine_Append(cl, chain)) {
+        ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
+        goto fail2;
+    }
+    
+    // add additional arguments
+    NCDValue *arg = NCDValue_ListNext(i->args, chain_arg);
+    while (arg) {
+        if (NCDValue_Type(arg) != NCDVALUE_STRING) {
+            ModuleLog(i, BLOG_ERROR, "wrong type");
+            goto fail2;
+        }
+        
+        if (!CmdLine_Append(cl, NCDValue_StringValue(arg))) {
+            ModuleLog(i, BLOG_ERROR, "CmdLine_Append failed");
+            goto fail2;
+        }
+        
+        arg = NCDValue_ListNext(i->args, arg);
+    }
+    
+    // finish
+    if (!CmdLine_Finish(cl)) {
+        ModuleLog(i, BLOG_ERROR, "CmdLine_Finish failed");
+        goto fail2;
+    }
+    
+    return 1;
+    
+fail2:
+    CmdLine_Free(cl);
+fail1:
+    free(*exec);
+fail0:
+    return 0;
+}
+
+static void * func_new (NCDModuleInst *i)
+{
+    return command_template_new(i, build_cmdline, BLOG_CURRENT_CHANNEL);
+}
+
+static const struct NCDModule modules[] = {
+    {
+        .type = "net.iptables.append",
+        .func_new = func_new,
+        .func_free = command_template_func_free,
+        .func_die = command_template_func_die
+    }, {
+        .type = NULL
+    }
+};
+
+const struct NCDModuleGroup ncdmodule_net_iptables = {
+    .modules = modules
+};