Add new task the vipmap task
authorNeutron Soutmun <neo.neutron@gmail.com>
Tue, 11 May 2010 17:34:20 +0000 (00:34 +0700)
committerNeutron Soutmun <neo.neutron@gmail.com>
Tue, 11 May 2010 17:34:20 +0000 (00:34 +0700)
15 files changed:
src/Makefile.am
src/rahunasd.h
src/rh-config.c
src/rh-config.h
src/rh-server.c
src/rh-server.h
src/rh-task-ipset.c
src/rh-task-vipmap.c [new file with mode: 0644]
src/rh-task-vipmap.h [new file with mode: 0644]
src/rh-task.c
src/rh-task.h
src/rh-xmlrpc-server.c
tools/rahunas-firewall.in
weblogin/login.php
weblogin/rahu_radius.class.php

index 52df01a..b8edd7a 100644 (file)
@@ -16,7 +16,8 @@ AM_CFLAGS = \
   -DRAHUNAS_LOG_DIR=\"$(localstatedir)/log/rahunas/\" \
   -DRAHUNAS_RUN_DIR=\"$(localstatedir)/run/\" \
   -DRAHUNAS_FIREWALL_WRAPPER=\"$(sbindir)/rahunas-firewall\" \
-  -DRAHUNAS_BANDWIDTH_WRAPPER=\"$(sbindir)/rahunas-bandwidth\"
+  -DRAHUNAS_BANDWIDTH_WRAPPER=\"$(sbindir)/rahunas-bandwidth\" \
+  -DRAHUNAS_VIPMAP_WRAPPER=\"$(sbindir)/rahunas-vipmap\"
 
 rahunasd_SOURCES = \
   rahunasd.c \
@@ -43,6 +44,8 @@ rahunasd_SOURCES = \
   rh-task-dbset.h \
   rh-task-bandwidth.c \
   rh-task-bandwidth.h \
+  rh-task-vipmap.c \
+  rh-task-vipmap.h \
   rh-radius.h \
   rh-config.c \
   rh-config.h
index 8582304..9e0ef0c 100644 (file)
@@ -61,6 +61,7 @@ struct rahunas_member {
   char *username;
   char *session_id;
   unsigned char mac_address[ETH_ALEN];
+  char *vip_ip;
 };
 
 void rh_free_member(struct rahunas_member *member);
index f17657d..da0a186 100755 (executable)
@@ -233,6 +233,13 @@ enum lcfg_status rahunas_visitor(const char *key, void *data, size_t size,
         if (config->rh_vserver.vipmap != NULL)
           free(config->rh_vserver.vipmap);
         config->rh_vserver.vipmap = strdup(value);
+
+        if (strncmp(config->rh_vserver.vipmap, "yes", strlen("yes")) == 0) {
+          config->rh_vserver.vipmap_enable = 1;
+
+          config->rh_vserver.vserver_vip_name =
+            g_strdup_printf ("%s-vip", config->rh_vserver.vserver_name);
+        }
       }
       break;
   }
index ce8541b..b8b09a8 100644 (file)
@@ -44,6 +44,7 @@ struct rahunas_main_config {
 
 struct rahunas_vserver_config {
   char *vserver_name;
+  char *vserver_vip_name;
   int  vserver_id;
   int  init_flag;
   char *dev_external;
@@ -84,6 +85,7 @@ struct rahunas_vserver_config {
   char *vipmap_attribute;
   char *vipmap_network;
   char *vipmap_fake_arp;
+  int  vipmap_enable;
 };
 
 union rahunas_config {
index dea93ea..8547265 100644 (file)
@@ -116,6 +116,11 @@ int register_vserver(struct main_server *ms, const char *vserver_cfg_file)
     .rh_vserver.nas_default_redirect = NULL,
     .rh_vserver.nas_default_language = NULL,
     .rh_vserver.nas_weblogin_template = NULL,
+    .rh_vserver.vipmap = NULL,
+    .rh_vserver.vipmap_attribute = NULL,
+    .rh_vserver.vipmap_network = NULL,
+    .rh_vserver.vipmap_fake_arp = NULL,
+    .rh_vserver.vipmap_enable = 0,
   };
 
   cfg_file = fopen(vserver_cfg_file, "r");
index af86e2d..2cdf2b1 100644 (file)
@@ -14,6 +14,7 @@ struct vserver {
   struct rahunas_vserver_config *dummy_config;
   struct rahunas_map *v_map;
   struct set *v_set;
+  struct set *v_vip_set;
 };
 
 struct main_server {
index e890d17..0a977f2 100644 (file)
@@ -65,6 +65,11 @@ static void init (struct vserver *vs)
     return;
 
   vs->v_set = set_adt_get(vs->vserver_config->vserver_name);
+
+  if (vs->vserver_config->vipmap_enable) {
+    vs->v_vip_set = set_adt_get(vs->vserver_config->vserver_vip_name);
+  }
+
   logmsg(RH_LOG_NORMAL, "[%s] Task IPSET initialize..",
          vs->vserver_config->vserver_name);  
 
@@ -74,6 +79,10 @@ static void init (struct vserver *vs)
 
   /* Ensure the set is empty */
   set_flush(vs->vserver_config->vserver_name);
+
+  if (vs->vserver_config->vipmap_enable) {
+    set_flush(vs->vserver_config->vserver_vip_name);
+  }
 }
 
 /* Cleanup */
@@ -88,7 +97,14 @@ static void cleanup (struct vserver *vs)
   walk_through_set(&set_cleanup, vs);
 
   set_flush(vs->vserver_config->vserver_name);
+
+  if (vs->vserver_config->vserver_vip_name != NULL)
+    set_flush(vs->vserver_config->vserver_vip_name);
+
   rh_free(&(vs->v_set));
+
+  if (vs->v_vip_set != NULL)
+    rh_free(&(vs->v_vip_set));
 }
 
 /* Start session task */
@@ -100,6 +116,12 @@ static int startsess (struct vserver *vs, struct task_req *req)
 
   res = set_adtip_nb(vs->v_set, &ip, req->mac_address, IP_SET_OP_ADD_IP);
 
+  if (vs->vserver_config->vipmap_enable && req->vip_user)
+    {
+      res = set_adtip_nb(vs->v_vip_set, &ip, req->mac_address,
+                         IP_SET_OP_ADD_IP);
+    }
+
   return res;
 }
 
@@ -112,6 +134,12 @@ static int stopsess  (struct vserver *vs, struct task_req *req)
 
   res = set_adtip_nb(vs->v_set, &ip, req->mac_address, IP_SET_OP_DEL_IP);
 
+  if (vs->vserver_config->vipmap_enable && req->vip_user)
+    {
+      res = set_adtip_nb(vs->v_vip_set, &ip, req->mac_address,
+                         IP_SET_OP_DEL_IP);
+    }
+
   return res;
 }
 
diff --git a/src/rh-task-vipmap.c b/src/rh-task-vipmap.c
new file mode 100644 (file)
index 0000000..1cf3c68
--- /dev/null
@@ -0,0 +1,237 @@
+/**
+ * RahuNAS task vipmap implementation 
+ * Author: Neutron Soutmun <neo.neutron@gmail.com>
+ * Date:   2010-05-11
+ */
+
+#include <stdlib.h>
+#include <syslog.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <time.h>
+#include <string.h>
+#include <libgda/libgda.h>
+#include "rahunasd.h"
+#include "rh-task.h"
+#include "rh-task-vipmap.h"
+#include "rh-task-memset.h"
+#include "rh-ipset.h"
+#include "rh-utils.h"
+
+GList *vipmap = NULL;
+
+int vipmap_exec(struct vserver *vs, char *const args[])
+{
+  pid_t ws;
+  pid_t pid;
+  int status;
+  int exec_pipe[2];
+  char buffer[150];
+  char *endline = NULL;
+  int ret = 0;
+  int fd = 0;
+  
+  memset(buffer, '\0', sizeof(buffer));
+
+  if (pipe(exec_pipe) == -1) {
+    logmsg(RH_LOG_ERROR, "Error: pipe()");
+    return -1;
+  }
+  DP("pipe0=%d,pipe1=%d", exec_pipe[0], exec_pipe[1]);
+
+  pid = vfork();
+  dup2(exec_pipe[1], STDOUT_FILENO);
+
+  if (pid == 0) {
+    // Child
+    execv(RAHUNAS_VIPMAP_WRAPPER, args);
+  } else if (pid < 0) {
+    // Fork error
+    logmsg(RH_LOG_ERROR, "Error: vfork()"); 
+    ret = -1;
+  } else {
+    // Parent
+    ws = waitpid(pid, &status, 0);
+
+    DP("VIP map: Return (%d)", WEXITSTATUS(status));
+
+    // Return message log
+    DP("Read message");
+    read(exec_pipe[0], buffer, sizeof(buffer));
+
+    if (buffer != NULL) {
+      DP("Got message: %s", buffer);
+      endline = strstr(buffer, "\n");
+      if (endline != NULL) 
+        *endline = '\0';
+
+      if (vs != NULL) {
+        logmsg(RH_LOG_NORMAL, "[%s] VIP map: %s", 
+          vs->vserver_config->vserver_name, buffer);
+      } else {
+        logmsg(RH_LOG_NORMAL, "[main server] VIP map: %s", buffer);
+      }
+    }
+
+    if (WIFEXITED(status)) {
+      ret = WEXITSTATUS(status);
+    } else {
+      ret = -1;
+    } 
+  }
+
+  if ((buffer != NULL) && (strncmp (buffer, "NOT COMPLETED", 13) == 0))
+    ret = -2;  // Not complete need to retry
+
+  close(exec_pipe[0]);
+  close(exec_pipe[1]);
+  return ret;
+}
+
+int vipmap_add(struct vserver *vs, struct vipmap_req *req)
+{
+  char *args[6];
+
+  DP("VIP map: add");
+
+  args[0] = RAHUNAS_VIPMAP_WRAPPER;
+  args[1] = "add";
+  args[2] = vs->vserver_config->vserver_name; 
+  args[3] = req->ip;
+  args[4] = req->vip_ip;
+  args[5] = (char *) 0;
+
+  return vipmap_exec (vs, args);
+}
+
+int vipmap_del(struct vserver *vs, struct vipmap_req *req)
+{
+  char *args[6];
+
+  DP("VIP map: add");
+
+  args[0] = RAHUNAS_VIPMAP_WRAPPER;
+  args[1] = "del";
+  args[2] = vs->vserver_config->vserver_name; 
+  args[3] = req->ip;
+  args[4] = req->vip_ip;
+  args[5] = (char *) 0;
+
+  return vipmap_exec (vs, args);
+}
+
+
+/* Start service task */
+static int startservice ()
+{
+  /* Do nothing */
+  return 0;
+}
+
+/* Stop service task */
+static int stopservice  ()
+{
+  /* Do nothing */
+  return 0;
+}
+
+/* Initialize */
+static void init (struct vserver *vs)
+{
+  /* Do nothing */
+}
+
+/* Cleanup */
+static void cleanup (struct vserver *vs)
+{
+  /* Do nothing */
+}
+
+/* Start session task */
+static int startsess (struct vserver *vs, struct task_req *req)
+{
+  struct vipmap_req vip_req;
+  GList *member_node = NULL;
+  struct rahunas_member *member = NULL;
+
+  member_node = member_get_node_by_id(vs, req->id);
+  if (member_node == NULL)
+    return -1;
+
+  member = (struct rahunas_member *) member_node->data;
+
+  snprintf(vip_req.ip, sizeof (vip_req.ip), "%s", idtoip(vs->v_map, req->id));
+  snprintf(vip_req.vip_ip, sizeof (vip_req.vip_ip), "%s",
+           idtoip(vs->v_map, req->id));
+
+  vipmap_add(vs, &vip_req);
+  return 0;
+}
+
+/* Stop session task */
+static int stopsess (struct vserver *vs, struct task_req *req)
+{
+  struct vipmap_req vip_req;
+  GList *member_node = NULL;
+  struct rahunas_member *member = NULL;
+
+  member_node = member_get_node_by_id(vs, req->id);
+  if (member_node == NULL)
+    return -1;
+
+  member = (struct rahunas_member *) member_node->data;
+
+  snprintf(vip_req.ip, sizeof (vip_req.ip), "%s", idtoip(vs->v_map, req->id));
+  snprintf(vip_req.vip_ip, sizeof (vip_req.vip_ip), "%s",
+           idtoip(vs->v_map, req->id));
+
+  vipmap_del(vs, &vip_req);
+
+  return 0;
+}
+
+/* Commit start session task */
+static int commitstartsess (struct vserver *vs, struct task_req *req)
+{
+  /* Do nothing or need to implement */
+}
+
+/* Commit stop session task */
+static int commitstopsess  (struct vserver *vs, struct task_req *req)
+{
+  /* Do nothing or need to implement */
+}
+
+/* Rollback start session task */
+static int rollbackstartsess (struct vserver *vs, struct task_req *req)
+{
+  /* Do nothing or need to implement */
+}
+
+/* Rollback stop session task */
+static int rollbackstopsess  (struct vserver *vs, struct task_req *req)
+{
+  /* Do nothing or need to implement */
+}
+
+static struct task task_vipmap = {
+  .taskname = "VIPMAP",
+  .taskprio = 15,
+  .init = &init,
+  .cleanup = &cleanup,
+  .startservice = &startservice,
+  .stopservice = &stopservice,
+  .startsess = &startsess,
+  .stopsess = &stopsess,
+  .commitstartsess = &commitstartsess,
+  .commitstopsess = &commitstopsess,
+  .rollbackstartsess = &rollbackstartsess,
+  .rollbackstopsess = &rollbackstopsess,
+};
+
+void rh_task_vipmap_reg(struct main_server *ms) {
+  task_register(ms, &task_vipmap);
+}
diff --git a/src/rh-task-vipmap.h b/src/rh-task-vipmap.h
new file mode 100644 (file)
index 0000000..edde247
--- /dev/null
@@ -0,0 +1,17 @@
+/**
+ * RahuNAS task vipmap implementation 
+ * Author: Neutron Soutmun <neo.neutron@gmail.com>
+ * Date:   2010-05-11
+ */
+#ifndef __RH_TASK_VIPMAP_H
+#define __RH_TASK_VIPMAP_H
+
+struct vipmap_req {
+  char ip[16];
+  char vip_ip[16];
+};
+
+extern void rh_task_vipmap_reg(struct main_server *ms);
+
+#endif // __RH_TASK_VIPMAP_H
+
index 37fb06a..ed48cd7 100644 (file)
@@ -11,6 +11,7 @@
 #include "rh-task-ipset.h"
 #include "rh-task-dbset.h"
 #include "rh-task-bandwidth.h"
+#include "rh-task-vipmap.h"
 
 void task_register(struct main_server *ms, struct task *task)
 {
@@ -58,6 +59,8 @@ void rh_task_register(struct main_server *ms)
     if (ms->main_config->bandwidth_shape)
       rh_task_bandwidth_reg(ms);
 
+    rh_task_vipmap_reg(ms);
+
     rh_task_dbset_reg(ms);
     task_registered = 1;
   }
index 78f03eb..ffbe22b 100644 (file)
@@ -23,6 +23,8 @@ struct task_req {
   unsigned long bandwidth_max_down;
   unsigned long bandwidth_max_up;
   unsigned short req_opt;
+  unsigned int  vip_user;
+  const char *vip_ip;
 };
 
 struct task {
index 59a6b78..866e7c5 100644 (file)
@@ -34,6 +34,7 @@ int do_startsession(GNetXmlRpcServer *server,
   gchar *session_timeout = NULL;
   gchar *bandwidth_max_down = NULL;
   gchar *bandwidth_max_up = NULL;
+  gchar *vip_user = NULL;
   gchar *vserver_id = NULL;
   uint32_t id;
   GList *member_node = NULL;
@@ -51,7 +52,8 @@ int do_startsession(GNetXmlRpcServer *server,
   session_timeout    = rh_string_get_sep(param, "|", 5);
   bandwidth_max_down = rh_string_get_sep(param, "|", 6);
   bandwidth_max_up   = rh_string_get_sep(param, "|", 7);
-  vserver_id         = rh_string_get_sep(param, "|", 8);
+  vip_user           = rh_string_get_sep(param, "|", 8);
+  vserver_id         = rh_string_get_sep(param, "|", 9);
 
   if (ip == NULL || username == NULL || session_id == NULL 
       || vserver_id == NULL)
@@ -101,15 +103,18 @@ int do_startsession(GNetXmlRpcServer *server,
   else
     req.bandwidth_max_up = 0;
 
+  req.vip_user = atoi (vip_user);
+
   rh_task_startsess(vs, &req);
   member_node = member_get_node_by_id(vs, id);
 
 greeting:
   if (member_node != NULL) {
     member = (struct rahunas_member *)member_node->data;
-    *reply_string = g_strdup_printf("Greeting! Got: IP %s, User %s, ID %s", 
+    *reply_string = g_strdup_printf("Greeting! Got: IP %s, User %s, ID %s, "
+                                    "VIP-IP %s",
                                     ip, member->username, 
-                                    member->session_id);
+                                    member->session_id, "");
     goto cleanup;
   }
 
@@ -126,6 +131,7 @@ cleanup:
   g_free(session_timeout);
   g_free(bandwidth_max_down);
   g_free(bandwidth_max_up);
+  g_free(vip_user);
   g_free(vserver_id);
   return 0;
 }
index 6ada185..6a700c0 100755 (executable)
@@ -677,6 +677,8 @@ rules () {
     if [ "$VIPMAP" = "yes" ]; then
       $IPTABLES -t nat -A $CHAIN_NAT_PREROUTING \
         -m set --set ${SETNAME}-vip src -j $CHAIN_NAT_VIP_PREROUTING
+
+      $IPTABLES -t nat -A $CHAIN_NAT_VIP_PREROUTING -j ACCEPT
     fi
 
     if [ "$PROXY" = "transparent" ]; then
index ff1b202..4397a5a 100644 (file)
@@ -45,6 +45,7 @@ require_once 'networkchk.php';
 $ip = $_SERVER['REMOTE_ADDR'];
 $config = get_config_by_network($ip, $config_list);
 $vserver_id = $config["VSERVER_ID"];
+$vip_user = 0;
 
 $forward = false;
 $LogoutURL  = $config['NAS_LOGIN_PROTO'] . "://" . $config['NAS_LOGIN_HOST'];
@@ -101,6 +102,11 @@ if (!empty($_POST['user']) && !empty($_POST['passwd'])) {
     $racct->calling_station_id = returnMacAddress();
     $racct->gen_session_id();
 
+    if ($config["VIPMAP"] == "yes" &&
+          !empty ($rauth->attributes[$config["VIPMAP_ATTRIBUTE"]])) {
+      $vip_user = 1;
+    }
+
 
     try {
       $prepareData = array (
@@ -110,12 +116,19 @@ if (!empty($_POST['user']) && !empty($_POST['passwd'])) {
         "MAC" => returnMacAddress(),
         "Session-Timeout" => $rauth->attributes['session_timeout'],
         "Bandwidth-Max-Down" => $rauth->attributes['WISPr-Bandwidth-Max-Down'],
-        "Bandwidth-Max-Up" => $rauth->attributes['WISPr-Bandwidth-Max-Up']);
+        "Bandwidth-Max-Up" => $rauth->attributes['WISPr-Bandwidth-Max-Up'],
+        "Vip_User" => $vip_user,
+      );
       $result = $xmlrpc->do_startsession($vserver_id, $prepareData);
       if (strstr($result,"Client already login")) {
         $message = get_message('ERR_ALREADY_LOGIN');
         $forward = false;
       } else if (strstr($result, "Greeting")) {
+        $split = explode ("VIP-IP ", $result);
+        $called_station_id = $split[1];
+        if (!empty ($called_station_id))
+          $racct->called_station_id = $called_station_id;
+
         $racct->acctStart();
       } else if (strstr($result, "Invalid IP Address")) {
         $message = get_message('ERR_INVALID_IP');
index a72db1c..55c213b 100644 (file)
@@ -170,6 +170,7 @@ class rahu_radius_acct {
   var $secret;
   var $framed_ip_address;
   var $calling_station_id;
+  var $called_station_id;
   var $terminate_cause;
   var $nas_identifier;
   var $nas_ip_address;
@@ -228,6 +229,7 @@ class rahu_radius_acct {
     $racct->putAttribute(RADIUS_NAS_IDENTIFIER, $this->nas_identifier);
     $racct->putAttribute(RADIUS_NAS_IP_ADDRESS, ip2long($this->nas_ip_address));
     $racct->putAttribute(RADIUS_NAS_PORT, $this->nas_port);
+    $racct->putAttribute(RADIUS_CALLED_STATION_ID, $this->called_station_id);
 
     switch($accttype) {
       case "Start":