File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / coova-chilli / src / main-query.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 22:48:25 2012 UTC (12 years, 10 months ago) by misho
Branches: coova-chilli, MAIN
CVS tags: v1_0_12, HEAD
coova-chilli

/* 
 * chilli - ChilliSpot.org. A Wireless LAN Access Point Controller.
 * Copyright (C) 2006 PicoPoint B.V.
 * Copyright (c) 2006-2007 David Bird <david@coova.com>
 *
 * The contents of this file may be used under the terms of the GNU
 * General Public License Version 2, provided that the above copyright
 * notice and this permission notice is included in all copies or
 * substantial portions of the software.
 * 
 */

#include "system.h"
#include "syserr.h"
#include "cmdline.h"
#include "dhcp.h"
#include "radius.h"
#include "radius_chillispot.h"
#include "radius_wispr.h"
#include "redir.h"
#include "chilli.h"
#include "options.h"
#include "cmdsock.h"

static int usage(char *program) {
  fprintf(stderr, "Usage: %s [ -s <socket> ] <command> [<argument>]\n", program);
  fprintf(stderr, "  socket = full path to UNIX domain socket (e.g. /var/run/chilli.sock)\n");
  /*  fprintf(stderr, "           TCP socket port, or ip:port, to bind to (e.g. 1999)\n"); */
  return 1;
}

typedef struct _cmd_info {
  int type;
  char *command;
  char *desc;
} cmd_info;

static cmd_info commands[] = {
  { CMDSOCK_LIST,          "list",          NULL },
  { CMDSOCK_ROUTE,         "route",         NULL },
  { CMDSOCK_DHCP_LIST,     "dhcp-list",     NULL },
  { CMDSOCK_DHCP_RELEASE,  "dhcp-release",  NULL },
  { CMDSOCK_AUTHORIZE,     "authorize",     NULL },
  { CMDSOCK_DHCP_RELEASE,  "logout",        NULL },
  { CMDSOCK_DHCP_RELEASE,  "logoff",        NULL },
  { CMDSOCK_DHCP_DROP,     "drop",          NULL },
  { CMDSOCK_DHCP_DROP,     "block",         NULL },
  { 0, NULL, NULL }
};

int main(int argc, char **argv) {
  /*
   *   chilli_query [ -s <unix-socket> ] <command> [<argument>]
   *   (or maybe this should get the unix-socket from the config file)
   */

  char *cmdsock = DEFCMDSOCK;
  int s, len;
  struct sockaddr_un remote;
  struct cmdsock_request request;
  char line[1024], *cmd;
  int argidx = 1;

  if (argc < 2) return usage(argv[0]);

  if (*argv[argidx] == '/') {
    /* for backward support, ignore a unix-socket given as first arg */
    if (argc < 3) return usage(argv[0]);
    cmdsock = argv[argidx++];
  } 
  
  memset(&request,0,sizeof(request));

  while (argidx < argc && *argv[argidx] == '-') {
    if (!strcmp(argv[argidx], "-s")) {
      argidx++;
      if (argidx >= argc) return usage(argv[0]);
      cmdsock = argv[argidx++];
    } else if (!strcmp(argv[argidx], "-json")) {
      request.options |= CMDSOCK_OPT_JSON;
      argidx++;
    }
  }

  if (argidx >= argc) return usage(argv[0]);

  cmd = argv[argidx++];
  for (s = 0; commands[s].command; s++) {
    if (!strcmp(cmd, commands[s].command)) {
      request.type = commands[s].type;
      switch(request.type) {
      case CMDSOCK_AUTHORIZE:
	{
	  struct arguments {
	    char *name;
	    int type;    /* 0=string, 1=integer, 2=ip */
	    int length;
	    void *field;
	    char *desc;
	    char *flag;
	    char flagbit;
	  } args[] = {
	    { "ip", 2, 
	      sizeof(request.data.sess.ip),
	      &request.data.sess.ip,
	      "IP of client to authorize",0,0 },
	    { "sessionid", 0, 
	      sizeof(request.data.sess.sessionid),
	      request.data.sess.sessionid,
	      "Session-id to authorize",0,0 },
	    { "username", 0, 
	      sizeof(request.data.sess.username),
	      request.data.sess.username,
	      "Username to use in RADIUS Accounting",0,0 },
	    { "sessiontimeout", 1, 
	      sizeof(request.data.sess.params.sessiontimeout),
	      &request.data.sess.params.sessiontimeout,
	      "Max session time (in seconds)",0,0 },
	    { "maxoctets", 1, 
	      sizeof(request.data.sess.params.maxtotaloctets),
	      &request.data.sess.params.maxtotaloctets,
	      "Max up/down octets (bytes)",0,0 },
	    { "maxbwup", 1, 
	      sizeof(request.data.sess.params.bandwidthmaxup),
	      &request.data.sess.params.bandwidthmaxup,
	      "Max bandwidth up",0,0 },
	    { "maxbwdown", 1, 
	      sizeof(request.data.sess.params.bandwidthmaxdown),
	      &request.data.sess.params.bandwidthmaxdown,
	      "Max bandwidth down",0,0 },
	    { "splash", 0, 
	      sizeof(request.data.sess.params.url),
	      &request.data.sess.params.url,
	      "Set splash page",
	      &request.data.sess.params.flags, REQUIRE_UAM_SPLASH },
	    { "routeidx", 1, 
	      sizeof(request.data.sess.params.routeidx),
	      &request.data.sess.params.routeidx,
	      "Route interface index",  0, 0 },
	    /* more... */
	  };
	  int count = sizeof(args)/sizeof(struct arguments);
	  int pos = argidx;
	  argc -= argidx;
	  while(argc > 0) {
	    int i;

	    for (i=0; i<count; i++) {

	      if (!strcmp(argv[pos],args[i].name)) {

		if (argc == 1) {
		  fprintf(stderr, "Argument %s requires a value\n", argv[pos]);
		  return usage(argv[0]);
		}
	  
		if (args[i].flag) {
		  *(args[i].flag) |=args[i].flagbit;
		}

		switch(args[i].type) {
		case 0:
		  strncpy(((char *)args[i].field), argv[pos+1], args[i].length-1);
		  break;
		case 1:
		  switch(args[i].length) {
		  case 1:
		    *((uint8_t *)args[i].field) = (uint8_t)atoi(argv[pos+1]);
		    break;
		  case 2:
		    *((uint16_t *)args[i].field) = (uint16_t)atoi(argv[pos+1]);
		    break;
		  case 4:
		    *((uint32_t *)args[i].field) = (uint32_t)atoi(argv[pos+1]);
		    break;
		  }
		  break;
		case 2:
		  if (!inet_aton(argv[pos+1], ((struct in_addr *)args[i].field))) {
		    fprintf(stderr, "Invalid IP Address: %s\n", argv[pos+1]);
		    return usage(argv[0]);
		  }
		  break;
		}
		break;
	      }
	    }

	    if (i == count) {
	      fprintf(stderr, "Unknown argument: %s\n", argv[pos]);
	      fprintf(stderr, "Use:\n");
	      for (i=0; i<count; i++) {
		fprintf(stderr, "  %-15s<value>  - type: %-6s - %s\n", 
			args[i].name, 
			args[i].type == 0 ? "string" :
			args[i].type == 1 ? "long" :
			args[i].type == 2 ? "int" :
			args[i].type == 3 ? "ip" :
			"unknown", args[i].desc);
	      }
	      fprintf(stderr, "The ip and/or sessionid is required.\n");
	      return usage(argv[0]);
	    }

	    argc -= 2;
	    pos += 2;
	  }
	}
	break;
      case CMDSOCK_DHCP_DROP:
      case CMDSOCK_DHCP_RELEASE:
	{
	  unsigned int temp[PKT_ETH_ALEN];
	  char macstr[RADIUS_ATTR_VLEN];
	  int macstrlen;
	  int i;

	  if (argc < argidx+1) {
	    fprintf(stderr, "%s requires a MAC address argument\n", cmd);
	    return usage(argv[0]);
	  }
	  
	  if ((macstrlen = strlen(argv[argidx])) >= (RADIUS_ATTR_VLEN-1)) {
	    fprintf(stderr, "%s: bad MAC address\n", argv[argidx]);
	    return -1;
	  }

	  memcpy(macstr, argv[argidx], macstrlen);
	  macstr[macstrlen] = 0;

	  for (i=0; i<macstrlen; i++) 
	    if (!isxdigit(macstr[i])) 
	      macstr[i] = 0x20;

	  if (sscanf(macstr, "%2x %2x %2x %2x %2x %2x", 
		     &temp[0], &temp[1], &temp[2], 
		     &temp[3], &temp[4], &temp[5]) != 6) {
	    fprintf(stderr, "%s: bad MAC address\n", argv[argidx]);
	    return -1;
	  }

	  for (i = 0; i < PKT_ETH_ALEN; i++) 
	    request.data.mac[i] = temp[i];

	  /* do another switch to pick up param configs for authorize */
	}
	break;
      case CMDSOCK_ROUTE:
	{
	  unsigned int temp[PKT_ETH_ALEN];
	  char macstr[RADIUS_ATTR_VLEN];
	  int macstrlen;
	  int routeidx;
	  int i;

	  if (argc < argidx + 2) {
	    break;
	  }
	  
	  if ((macstrlen = strlen(argv[argidx])) >= (RADIUS_ATTR_VLEN-1)) {
	    fprintf(stderr, "%s: bad MAC address\n", argv[argidx]);
	    break;
	  }

	  memcpy(macstr, argv[argidx], macstrlen);
	  macstr[macstrlen] = 0;

	  for (i=0; i<macstrlen; i++) 
	    if (!isxdigit(macstr[i])) 
	      macstr[i] = 0x20;

	  if (sscanf(macstr, "%2x %2x %2x %2x %2x %2x", 
		     &temp[0], &temp[1], &temp[2], 
		     &temp[3], &temp[4], &temp[5]) != 6) {
	    fprintf(stderr, "%s: bad MAC address\n", argv[argidx]);
	    break;
	  }

	  for (i = 0; i < PKT_ETH_ALEN; i++) 
	    request.data.mac[i] = temp[i];

	  argidx++;
	  request.data.sess.params.routeidx = atoi(argv[argidx]);

	  request.type = CMDSOCK_ROUTE_SET;

	  /* do another switch to pick up param configs for authorize */
	}
	break;
      }
      break;
    }
  }

  if (!commands[s].command) {
    fprintf(stderr,"unknown command: %s\n",cmd);
    exit(1);
  }

  if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) {
    perror("socket");
    exit(1);
  }

  remote.sun_family = AF_UNIX;
  strcpy(remote.sun_path, cmdsock);
  len = strlen(remote.sun_path) + sizeof(remote.sun_family);
  if (connect(s, (struct sockaddr *)&remote, len) == -1) {
    perror("connect");
    exit(1);
  }
  
  if (write(s, &request, sizeof(request)) != sizeof(request)) {
    perror("write");
    exit(1);
  }

  while((len = read(s, line, sizeof(line)-1)) > 0) 
    write(1, line, len);

  if (len < 0) 
    perror("read");

  shutdown(s,2);
  close(s);
  
  return 0;
}

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>