예제 #1
0
파일: ccp.c 프로젝트: ZRouter/ZRouter
void
CcpNgCtrlEvent(int type, void *cookie)
{
    Bund		b = NULL;
    union {
        u_char		buf[2048];
        struct ng_mesg	msg;
    }			u;
    char		raddr[NG_PATHSIZ];
    int			i, len;
    ng_ID_t		id;

    /* Read message */
    if ((len = NgRecvMsg(gCcpCsock, &u.msg, sizeof(u), raddr)) < 0) {
	Perror("CcpNgCtrlEvent: can't read message");
	return;
    }
    
    if (sscanf(raddr, "[%x]:", &id) != 1) {
	Log(LG_ERR, ("CcpNgCtrlEvent: can't decode sender id: '%s'",
    	    raddr));
	return;
    }
    
    for (i = 0; i < gNumBundles; i++) {
	if (gBundles[i] && !gBundles[i]->dead &&
		gBundles[i]->ccp.decomp_node_id == id) {
	    b = gBundles[i];
	    break;
	}
    }
    if (!b)
	return;

    /* Examine message */
    switch (u.msg.header.typecookie) {

#ifdef USE_NG_MPPC
	case NGM_MPPC_COOKIE:
#endif
#ifdef USE_NG_DEFLATE
	case NGM_DEFLATE_COOKIE:
#endif
#ifdef USE_NG_PRED1
	case NGM_PRED1_COOKIE:
#endif
    	    CcpRecvMsg(b, &u.msg, len);
        return;

	default:
	    /* Unknown message */
	    Log(LG_ERR, ("CcpNgCtrlEvent: rec'd unknown ctrl message, cookie=%d cmd=%d",
		u.msg.header.typecookie, u.msg.header.cmd));
    	    break;
    }

}
예제 #2
0
파일: msg.c 프로젝트: ele7enxxh/dtrace-pf
/*
 * Receive a control message and convert the arguments to ASCII
 */
int
NgRecvAsciiMsg(int cs, struct ng_mesg *reply, size_t replen, char *path)
{
	struct ng_mesg *msg, *ascii;
	int bufSize, errnosv;
	u_char *buf;

	/* Allocate buffer */
	bufSize = 2 * sizeof(*reply) + replen;
	if ((buf = malloc(bufSize)) == NULL)
		return (-1);
	msg = (struct ng_mesg *)buf;
	ascii = (struct ng_mesg *)msg->data;

	/* Get binary message */
	if (NgRecvMsg(cs, msg, bufSize, path) < 0)
		goto fail;
	memcpy(reply, msg, sizeof(*msg));

	/* Ask originating node to convert the arguments to ASCII */
	if (NgSendMsg(cs, path, NGM_GENERIC_COOKIE,
	    NGM_BINARY2ASCII, msg, sizeof(*msg) + msg->header.arglen) < 0)
		goto fail;
	if (NgRecvMsg(cs, msg, bufSize, NULL) < 0)
		goto fail;

	/* Copy result to client buffer */
	if (sizeof(*ascii) + ascii->header.arglen > replen) {
		errno = ERANGE;
fail:
		errnosv = errno;
		free(buf);
		errno = errnosv;
		return (-1);
	}
	strncpy(reply->data, ascii->data, ascii->header.arglen);

	/* Done */
	free(buf);
	return (0);
}
예제 #3
0
static int
ConfigCmd(int ac, char **av)
{
	u_char sbuf[sizeof(struct ng_mesg) + NG_TEXTRESPONSE];
	struct ng_mesg *const resp = (struct ng_mesg *) sbuf;
	char *const status = (char *) resp->data;
	char *path;
	char buf[NG_TEXTRESPONSE];
	int nostat = 0, i;

	/* Get arguments */
	if (ac < 2)
		return (CMDRTN_USAGE);
	path = av[1];

	*buf = '\0';
	for (i = 2; i < ac; i++) {
		if (i != 2)
			strcat(buf, " ");
		strcat(buf, av[i]);
	}
	
	/* Get node config summary */
	if (*buf != '\0')
		i = NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
	            NGM_TEXT_CONFIG, buf, strlen(buf) + 1);
	else
		i = NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
	            NGM_TEXT_CONFIG, NULL, 0);
	if (i < 0) {
		switch (errno) {
		case EINVAL:
			nostat = 1;
			break;
		default:
			warn("send msg");
			return (CMDRTN_ERROR);
		}
	} else {
		if (NgRecvMsg(csock, resp, sizeof(sbuf), NULL) < 0
		    || (resp->header.flags & NGF_RESP) == 0)
			nostat = 1;
	}

	/* Show it */
	if (nostat)
		printf("No config available for \"%s\"\n", path);
	else
		printf("Config for \"%s\":\n%s\n", path, status);
	return (CMDRTN_OK);
}
예제 #4
0
파일: msg.c 프로젝트: ele7enxxh/dtrace-pf
/*
 * Identical to NgRecvMsg() except buffer is dynamically allocated.
 */
int
NgAllocRecvMsg(int cs, struct ng_mesg **rep, char *path)
{
	int len;
	socklen_t optlen;

	optlen = sizeof(len);
	if (getsockopt(cs, SOL_SOCKET, SO_RCVBUF, &len, &optlen) == -1 ||
	    (*rep = malloc(len)) == NULL)
		return (-1);
	if ((len = NgRecvMsg(cs, *rep, len, path)) < 0)
		free(*rep);
	return (len);
}
예제 #5
0
static void
do_show(int version, void (*func)(struct ngnf_show_header *))
{
	struct ng_mesg *ng_mesg;
	struct ngnf_show_header req, *resp;
	int token, nread;

	ng_mesg = alloca(SORCVBUF_SIZE);

	req.version = version;
	req.hash_id = req.list_id = 0;

	for (;;) {
		/* request set of accounting records */
		token = NgSendMsg(cs, ng_path, NGM_NETFLOW_COOKIE,
		    NGM_NETFLOW_SHOW, (void *)&req, sizeof(req));
		if (token == -1)
			err(1, "NgSendMsg(NGM_NETFLOW_SHOW)");

		/* read reply */
		nread = NgRecvMsg(cs, ng_mesg, SORCVBUF_SIZE, NULL);
		if (nread == -1)
			err(1, "NgRecvMsg() failed");

		if (ng_mesg->header.token != token)
			err(1, "NgRecvMsg(NGM_NETFLOW_SHOW): token mismatch");

		resp = (struct ngnf_show_header *)ng_mesg->data;
		if ((ng_mesg->header.arglen < (sizeof(*resp))) ||
		    (ng_mesg->header.arglen < (sizeof(*resp) +
		    (resp->nentries * sizeof(struct flow_entry_data)))))
			err(1, "NgRecvMsg(NGM_NETFLOW_SHOW): arglen too small");

		(*func)(resp);

		if (resp->hash_id != 0)
			req.hash_id = resp->hash_id;
		else
			break;
		req.list_id = resp->list_id;
	}
}
예제 #6
0
static int
StatusCmd(int ac, char **av)
{
	u_char sbuf[sizeof(struct ng_mesg) + NG_TEXTRESPONSE];
	struct ng_mesg *const resp = (struct ng_mesg *) sbuf;
	char *const status = (char *) resp->data;
	char *path;
	int nostat = 0;

	/* Get arguments */
	switch (ac) {
	case 2:
		path = av[1];
		break;
	default:
		return (CMDRTN_USAGE);
	}

	/* Get node status summary */
	if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
	    NGM_TEXT_STATUS, NULL, 0) < 0) {
		switch (errno) {
		case EINVAL:
			nostat = 1;
			break;
		default:
			warn("send msg");
			return (CMDRTN_ERROR);
		}
	} else {
		if (NgRecvMsg(csock, resp, sizeof(sbuf), NULL) < 0
		    || (resp->header.flags & NGF_RESP) == 0)
			nostat = 1;
	}

	/* Show it */
	if (nostat)
		printf("No status available for \"%s\"\n", path);
	else
		printf("Status for \"%s\":\n%s\n", path, status);
	return (CMDRTN_OK);
}
예제 #7
0
/*
 * Input from the control socket.
 */
static struct ng_mesg *
csock_read(char *path)
{
	struct ng_mesg *mesg;
	int ret, err;

	if ((mesg = malloc(resbufsiz + 1)) == NULL) {
		stats[LEAF_begemotNgNoMems]++;
		syslog(LOG_CRIT, "out of memory");
		errno = ENOMEM;
		return (NULL);
	}
	if ((ret = NgRecvMsg(csock, mesg, resbufsiz + 1, path)) < 0) {
		err = errno;
		free(mesg);
		if (errno == EWOULDBLOCK) {
			errno = err;
			return (NULL);
		}
		stats[LEAF_begemotNgMsgReadErrs]++;
		syslog(LOG_WARNING, "read from csock: %m");
		errno = err;
		return (NULL);
	}
	if (ret == 0) {
		syslog(LOG_DEBUG, "node closed -- exiting");
		exit(0);
	}
	if ((size_t)ret > resbufsiz) {
		stats[LEAF_begemotNgTooLargeMsgs]++;
		syslog(LOG_WARNING, "ng message too large");
		free(mesg);
		errno = EFBIG;
		return (NULL);
	}
	return (mesg);
}
예제 #8
0
/*
 * Retrieve hook or database info
 */
static int
ip_account_get_info(int type, void *buf, int blen, int outgoing)
{
	int token, error;
	struct ng_mesg *ng_mesg;
	char path[NG_PATHLEN + 1];

	/* send control message */
	if ((token = ip_account_ctl(type, outgoing)) == -1)
		return (-1);

	/* read reply */
    if (ng_ready_for_read() != 1)
        return (-1);
	ng_mesg = alloca(sizeof(*ng_mesg) + blen);
	error = NgRecvMsg(ng_cs, ng_mesg, (sizeof(*ng_mesg) + blen), path);

	if (error == -1) {
		warn("NgRecvMsg(NGM_IPACCT_xINFO)");
		return (-1);
	}
	if (ng_mesg->header.token != token) {
		warnx("NgRecvMsg(NGM_IPACCT_xINFO): token mismatch");
		return (-1);
	}
	if (ng_mesg->header.arglen < blen) {
		warnx("NgRecvMsg(NGM_IPACCT_xINFO): arglen too small, "
		      "arglen = %d, blen = %d", 
		    ng_mesg->header.arglen, blen);
		return (-1);
	}

	bcopy(ng_mesg->data, buf, blen);

	return (0);
}
예제 #9
0
static void
ether_MessageIn(struct etherdevice *dev)
{
  char msgbuf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)];
  struct ng_mesg *rep = (struct ng_mesg *)msgbuf;
  struct ngpppoe_sts *sts = (struct ngpppoe_sts *)(msgbuf + sizeof *rep);
  char *end, unknown[14], sessionid[5];
  const char *msg;
  struct timeval t;
  fd_set *r;
  u_long slot;
  int asciilen, ret;

  if (dev->cs < 0)
    return;

  if ((r = mkfdset()) == NULL) {
    log_Printf(LogERROR, "DoLoop: Cannot create fd_set\n");
    return;
  }

  while (1) {
    zerofdset(r);
    FD_SET(dev->cs, r);
    t.tv_sec = t.tv_usec = 0;
    ret = select(dev->cs + 1, r, NULL, NULL, &t);

    if (ret <= 0)
      break;

    if (NgRecvMsg(dev->cs, rep, sizeof msgbuf, NULL) <= 0)
      break;

    if (rep->header.version != NG_VERSION) {
      log_Printf(LogWARN, "%ld: Unexpected netgraph version, expected %ld\n",
                 (long)rep->header.version, (long)NG_VERSION);
      break;
    }

    if (rep->header.typecookie != NGM_PPPOE_COOKIE) {
      log_Printf(LogWARN, "%ld: Unexpected netgraph cookie, expected %ld\n",
                 (long)rep->header.typecookie, (long)NGM_PPPOE_COOKIE);
      break;
    }

    asciilen = 0;
    switch (rep->header.cmd) {
      case NGM_PPPOE_SET_FLAG:	msg = "SET_FLAG";	break;
      case NGM_PPPOE_CONNECT:	msg = "CONNECT";	break;
      case NGM_PPPOE_LISTEN:	msg = "LISTEN";		break;
      case NGM_PPPOE_OFFER:	msg = "OFFER";		break;
      case NGM_PPPOE_SUCCESS:	msg = "SUCCESS";	break;
      case NGM_PPPOE_FAIL:	msg = "FAIL";		break;
      case NGM_PPPOE_CLOSE:	msg = "CLOSE";		break;
      case NGM_PPPOE_GET_STATUS:	msg = "GET_STATUS";	break;
      case NGM_PPPOE_ACNAME:
        msg = "ACNAME";
        if (setenv("ACNAME", sts->hook, 1) != 0)
          log_Printf(LogWARN, "setenv: cannot set ACNAME=%s: %m", sts->hook);
        asciilen = rep->header.arglen;
        break;
      case NGM_PPPOE_SESSIONID:
        msg = "SESSIONID";
        snprintf(sessionid, sizeof sessionid, "%04x", *(u_int16_t *)sts);
        if (setenv("SESSIONID", sessionid, 1) != 0)
          syslog(LOG_WARNING, "setenv: cannot set SESSIONID=%s: %m",
                 sessionid);
        /* Use this in preference to our interface index */
        slot = strtoul(sessionid, &end, 16);
        if (end != sessionid && *end == '\0')
            dev->slot = slot;
        break;
      default:
        snprintf(unknown, sizeof unknown, "<%d>", (int)rep->header.cmd);
        msg = unknown;
        break;
    }

    if (asciilen)
      log_Printf(LogPHASE, "Received NGM_PPPOE_%s (hook \"%.*s\")\n",
                 msg, asciilen, sts->hook);
    else
      log_Printf(LogPHASE, "Received NGM_PPPOE_%s\n", msg);

    switch (rep->header.cmd) {
      case NGM_PPPOE_SUCCESS:
        dev->connected = CARRIER_OK;
        break;
      case NGM_PPPOE_FAIL:
      case NGM_PPPOE_CLOSE:
        dev->connected = CARRIER_LOST;
        break;
    }
  }
  free(r);
}
예제 #10
0
파일: sock.c 프로젝트: edgar-pek/PerspicuOS
/*
 * Create a socket type node and give it the supplied name.
 * Return data and control sockets corresponding to the node.
 * Returns -1 if error and sets errno.
 */
int
NgMkSockNode(const char *name, int *csp, int *dsp)
{
	char namebuf[NG_NODESIZ];
	int cs = -1;		/* control socket */
	int ds = -1;		/* data socket */
	int errnosv;

	/* Empty name means no name */
	if (name && *name == 0)
		name = NULL;

	/* Create control socket; this also creates the netgraph node.
	   If we get an EPROTONOSUPPORT then the socket node type is
	   not loaded, so load it and try again. */
	if ((cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL)) < 0) {
		if (errno == EPROTONOSUPPORT) {
			if (kldload(NG_SOCKET_KLD) < 0) {
				errnosv = errno;
				if (_gNgDebugLevel >= 1)
					NGLOG("can't load %s", NG_SOCKET_KLD);
				goto errout;
			}
			cs = socket(AF_NETGRAPH, SOCK_DGRAM, NG_CONTROL);
			if (cs >= 0)
				goto gotNode;
		}
		errnosv = errno;
		if (_gNgDebugLevel >= 1)
			NGLOG("socket");
		goto errout;
	}

gotNode:
	/* Assign the node the desired name, if any */
	if (name != NULL) {
		u_char sbuf[NG_NODESIZ + NGSA_OVERHEAD];
		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;

		/* Assign name */
		strlcpy(sg->sg_data, name, NG_NODESIZ);
		sg->sg_family = AF_NETGRAPH;
		sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
		if (bind(cs, (struct sockaddr *) sg, sg->sg_len) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("bind(%s)", sg->sg_data);
			goto errout;
		}

		/* Save node name */
		strlcpy(namebuf, name, sizeof(namebuf));
	} else if (dsp != NULL) {
		u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
		struct ng_mesg *const resp = (struct ng_mesg *) rbuf;
		struct nodeinfo *const ni = (struct nodeinfo *) resp->data;

		/* Find out the node ID */
		if (NgSendMsg(cs, ".", NGM_GENERIC_COOKIE,
		    NGM_NODEINFO, NULL, 0) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("send nodeinfo");
			goto errout;
		}
		if (NgRecvMsg(cs, resp, sizeof(rbuf), NULL) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("recv nodeinfo");
			goto errout;
		}

		/* Save node "name" */
		snprintf(namebuf, sizeof(namebuf), "[%lx]", (u_long) ni->id);
	}

	/* Create data socket if desired */
	if (dsp != NULL) {
		u_char sbuf[NG_NODESIZ + 1 + NGSA_OVERHEAD];
		struct sockaddr_ng *const sg = (struct sockaddr_ng *) sbuf;

		/* Create data socket, initially just "floating" */
		if ((ds = socket(AF_NETGRAPH, SOCK_DGRAM, NG_DATA)) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("socket");
			goto errout;
		}

		/* Associate the data socket with the node */
		snprintf(sg->sg_data, NG_NODESIZ + 1, "%s:", namebuf);
		sg->sg_family = AF_NETGRAPH;
		sg->sg_len = strlen(sg->sg_data) + 1 + NGSA_OVERHEAD;
		if (connect(ds, (struct sockaddr *) sg, sg->sg_len) < 0) {
			errnosv = errno;
			if (_gNgDebugLevel >= 1)
				NGLOG("connect(%s)", sg->sg_data);
			goto errout;
		}
	}

	/* Return the socket(s) */
	if (csp)
		*csp = cs;
	else
		close(cs);
	if (dsp)
		*dsp = ds;
	return (0);

errout:
	/* Failed */
	if (cs >= 0)
		close(cs);
	if (ds >= 0)
		close(ds);
	errno = errnosv;
	return (-1);
}
예제 #11
0
파일: netgraph.c 프로젝트: coyizumi/cs111
void
netgraphprotopr(u_long off, const char *name, int af1 __unused,
    int proto __unused)
{
	struct ngpcb *this, *next;
	struct ngpcb ngpcb;
	struct socket sockb;
	int debug = 1;

	/* If symbol not found, try looking in the KLD module */
	if (off == 0) {
		if (debug)
			fprintf(stderr,
			    "Error reading symbols from ng_socket.ko");
		return;
	}

	/* Get pointer to first socket */
	kread(off, (char *)&this, sizeof(this));

	/* Get my own socket node */
	if (csock == -1)
		NgMkSockNode(NULL, &csock, NULL);

	for (; this != NULL; this = next) {
		u_char rbuf[sizeof(struct ng_mesg) + sizeof(struct nodeinfo)];
		struct ng_mesg *resp = (struct ng_mesg *) rbuf;
		struct nodeinfo *ni = (struct nodeinfo *) resp->data;
		char path[64];

		/* Read in ngpcb structure */
		kread((u_long)this, (char *)&ngpcb, sizeof(ngpcb));
		next = LIST_NEXT(&ngpcb, socks);

		/* Read in socket structure */
		kread((u_long)ngpcb.ng_socket, (char *)&sockb, sizeof(sockb));

		/* Check type of socket */
		if (strcmp(name, "ctrl") == 0 && ngpcb.type != NG_CONTROL)
			continue;
		if (strcmp(name, "data") == 0 && ngpcb.type != NG_DATA)
			continue;

		/* Do headline */
		if (first) {
			printf("Netgraph sockets\n");
			if (Aflag)
				printf("%-8.8s ", "PCB");
			printf("%-5.5s %-6.6s %-6.6s %-14.14s %s\n",
			    "Type", "Recv-Q", "Send-Q",
			    "Node Address", "#Hooks");
			first = 0;
		}

		/* Show socket */
		if (Aflag)
			printf("%8lx ", (u_long) this);
		printf("%-5.5s %6u %6u ",
		    name, sockb.so_rcv.sb_cc, sockb.so_snd.sb_cc);

		/* Get info on associated node */
		if (ngpcb.node_id == 0 || csock == -1)
			goto finish;
		snprintf(path, sizeof(path), "[%x]:", ngpcb.node_id);
		if (NgSendMsg(csock, path,
		    NGM_GENERIC_COOKIE, NGM_NODEINFO, NULL, 0) < 0)
			goto finish;
		if (NgRecvMsg(csock, resp, sizeof(rbuf), NULL) < 0)
			goto finish;

		/* Display associated node info */
		if (*ni->name != '\0')
			snprintf(path, sizeof(path), "%s:", ni->name);
		printf("%-14.14s %4d", path, ni->hooks);
finish:
		putchar('\n');
	}
}
예제 #12
0
static int
ConfigureNode(const char *prog, const char *iface, const char *provider,
              int cs, int ds, int debug, struct ngm_connect *ngc)
{
  /*
   * We're going to do this with the passed `ds' & `cs' descriptors:
   *
   * .---------.
   * |  ether  |
   * | <iface> |
   * `---------'
   *  (orphan)                                     ds    cs
   *     |                                         |     |
   *     |                                         |     |
   * (ethernet)                                    |     |
   * .---------.                                .-----------.
   * |  pppoe  |                                |  socket   |
   * | <iface> |(pppoe-<pid>)<---->(pppoe-<pid>)| <unnamed> |
   * `---------                                 `-----------'
   * (exec-<pid>)
   *     ^                .-----------.      .-------------.
   *     |                |   socket  |      | ppp -direct |
   *     `--->(exec-<pid>)| <unnamed> |--fd--|  provider   |
   *                      `-----------'      `-------------'
   *
   * where there are potentially many ppp processes running off of the
   * same PPPoE node.
   * The exec-<pid> hook isn't made 'till we Spawn().
   */

  char *epath, *spath;
  struct ngpppoe_init_data *data;
  const struct hooklist *hlist;
  const struct nodeinfo *ninfo;
  const struct linkinfo *nlink;
  struct ngm_mkpeer mkp;
  struct ng_mesg *resp;
  u_char rbuf[2048];
  int f, plen;

  /*
   * Ask for a list of hooks attached to the "ether" node.  This node should
   * magically exist as a way of hooking stuff onto an ethernet device
   */
  epath = (char *)alloca(strlen(iface) + 2);
  sprintf(epath, "%s:", iface);

  if (debug)
    fprintf(stderr, "Sending NGM_LISTHOOKS to %s\n", epath);

  if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0) < 0) {
    if (errno == ENOENT)
      fprintf(stderr, "%s Cannot send a netgraph message: Invalid interface\n",
              epath);
    else
      fprintf(stderr, "%s Cannot send a netgraph message: %s\n",
              epath, strerror(errno));
    return EX_UNAVAILABLE;
  }

  /* Get our list back */
  resp = (struct ng_mesg *)rbuf;
  if (NgRecvMsg(cs, resp, sizeof rbuf, NULL) <= 0) {
    perror("Cannot get netgraph response");
    return EX_UNAVAILABLE;
  }

  hlist = (const struct hooklist *)resp->data;
  ninfo = &hlist->nodeinfo;

  if (debug)
    fprintf(stderr, "Got reply from id [%x]: Type %s with %d hooks\n",
            ninfo->id, ninfo->type, ninfo->hooks);

  /* Make sure we've got the right type of node */
  if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE, sizeof NG_ETHER_NODE_TYPE - 1)) {
    fprintf(stderr, "%s Unexpected node type ``%s'' (wanted ``"
            NG_ETHER_NODE_TYPE "'')\n", epath, ninfo->type);
    return EX_DATAERR;
  }

  /* look for a hook already attached.  */
  for (f = 0; f < ninfo->hooks; f++) {
    nlink = &hlist->link[f];

    if (debug)
      fprintf(stderr, "  Got [%x]:%s -> [%x]:%s\n", ninfo->id,
              nlink->ourhook, nlink->nodeinfo.id, nlink->peerhook);

    if (!strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) ||
        !strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT)) {
      /*
       * Something is using the data coming out of this `ether' node.
       * If it's a PPPoE node, we use that node, otherwise we complain that
       * someone else is using the node.
       */
      if (strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE)) {
        fprintf(stderr, "%s Node type %s is currently active\n",
                epath, nlink->nodeinfo.type);
        return EX_UNAVAILABLE;
      }
      break;
    }
  }

  if (f == ninfo->hooks) {
    /*
     * Create a new PPPoE node connected to the `ether' node using
     * the magic `orphan' and `ethernet' hooks
     */
    snprintf(mkp.type, sizeof mkp.type, "%s", NG_PPPOE_NODE_TYPE);
    snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", NG_ETHER_HOOK_ORPHAN);
    snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", NG_PPPOE_HOOK_ETHERNET);

    if (debug)
      fprintf(stderr, "Send MKPEER: %s%s -> [type %s]:%s\n", epath,
              mkp.ourhook, mkp.type, mkp.peerhook);

    if (NgSendMsg(cs, epath, NGM_GENERIC_COOKIE,
                  NGM_MKPEER, &mkp, sizeof mkp) < 0) {
      fprintf(stderr, "%s Cannot create a peer PPPoE node: %s\n",
              epath, strerror(errno));
      return EX_OSERR;
    }
  }

  /* Connect the PPPoE node to our socket node.  */
  snprintf(ngc->path, sizeof ngc->path, "%s%s", epath, NG_ETHER_HOOK_ORPHAN);
  snprintf(ngc->ourhook, sizeof ngc->ourhook, "pppoe-%ld", (long)getpid());
  memcpy(ngc->peerhook, ngc->ourhook, sizeof ngc->peerhook);

  if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE,
                NGM_CONNECT, ngc, sizeof *ngc) < 0) {
    perror("Cannot CONNECT PPPoE and socket nodes");
    return EX_OSERR;
  }

  plen = strlen(provider);

  data = (struct ngpppoe_init_data *)alloca(sizeof *data + plen);
  snprintf(data->hook, sizeof data->hook, "%s", ngc->peerhook);
  memcpy(data->data, provider, plen);
  data->data_len = plen;

  spath = (char *)alloca(strlen(ngc->peerhook) + 3);
  strcpy(spath, ".:");
  strcpy(spath + 2, ngc->ourhook);

  if (debug) {
    if (provider)
      fprintf(stderr, "Sending PPPOE_LISTEN to %s, provider %s\n",
              spath, provider);
    else
      fprintf(stderr, "Sending PPPOE_LISTEN to %s\n", spath);
  }

  if (NgSendMsg(cs, spath, NGM_PPPOE_COOKIE, NGM_PPPOE_LISTEN,
                data, sizeof *data + plen) == -1) {
    fprintf(stderr, "%s: Cannot LISTEN on netgraph node: %s\n",
            spath, strerror(errno));
    return EX_OSERR;
  }

  return 0;
}
예제 #13
0
static void
Spawn(const char *prog, const char *acname, const char *provider,
      const char *exec, struct ngm_connect ngc, int cs, int ds, void *request,
      int sz, int debug)
{
  char msgbuf[sizeof(struct ng_mesg) + sizeof(struct ngpppoe_sts)];
  struct ng_mesg *rep = (struct ng_mesg *)msgbuf;
  struct ngpppoe_sts *sts = (struct ngpppoe_sts *)(msgbuf + sizeof *rep);
  struct ngpppoe_init_data *data;
  char env[18], unknown[14], sessionid[5], *path;
  unsigned char *macaddr;
  const char *msg;
  int ret, slen;

  switch ((ret = fork())) {
    case -1:
      syslog(LOG_ERR, "fork: %m");
      break;

    case 0:
      switch (fork()) {
        case 0:
          break;
        case -1:
          _exit(errno);
        default:
          _exit(0);
      }
      close(cs);
      close(ds);

      /* Create a new socket node */
      if (debug)
        syslog(LOG_INFO, "Creating a new socket node");

      if (NgMkSockNode(NULL, &cs, &ds) == -1) {
        syslog(LOG_ERR, "Cannot create netgraph socket node: %m");
        _exit(EX_CANTCREAT);
      }

      /* Connect the PPPoE node to our new socket node.  */
      snprintf(ngc.ourhook, sizeof ngc.ourhook, "exec-%ld", (long)getpid());
      memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook);

      if (debug)
        syslog(LOG_INFO, "Sending CONNECT from .:%s -> %s.%s",
               ngc.ourhook, ngc.path, ngc.peerhook);
      if (NgSendMsg(cs, ".:", NGM_GENERIC_COOKIE,
                    NGM_CONNECT, &ngc, sizeof ngc) < 0) {
        syslog(LOG_ERR, "Cannot CONNECT PPPoE and socket nodes: %m");
        _exit(EX_OSERR);
      }

      /*
       * If we tell the socket node not to LINGER, it will go away when
       * the last hook is removed.
       */
      if (debug)
        syslog(LOG_INFO, "Sending NGM_SOCK_CMD_NOLINGER to socket");
      if (NgSendMsg(cs, ".:", NGM_SOCKET_COOKIE,
                    NGM_SOCK_CMD_NOLINGER, NULL, 0) < 0) {
        syslog(LOG_ERR, "Cannot send NGM_SOCK_CMD_NOLINGER: %m");
        _exit(EX_OSERR);
      }

      /* Put the PPPoE node into OFFER mode */
      slen = strlen(acname);
      data = (struct ngpppoe_init_data *)alloca(sizeof *data + slen);
      snprintf(data->hook, sizeof data->hook, "%s", ngc.ourhook);
      memcpy(data->data, acname, slen);
      data->data_len = slen;

      path = (char *)alloca(strlen(ngc.ourhook) + 3);
      strcpy(path, ".:");
      strcpy(path + 2, ngc.ourhook);

      syslog(LOG_INFO, "Offering to %s as access concentrator %s",
             path, acname);
      if (NgSendMsg(cs, path, NGM_PPPOE_COOKIE, NGM_PPPOE_OFFER,
                    data, sizeof *data + slen) == -1) {
        syslog(LOG_INFO, "%s: Cannot OFFER on netgraph node: %m", path);
        _exit(EX_OSERR);
      }
      /* If we have a provider code, set it */
      if (provider) {
        slen = strlen(provider);
        data = (struct ngpppoe_init_data *)alloca(sizeof *data + slen);
        snprintf(data->hook, sizeof data->hook, "%s", ngc.ourhook);
        memcpy(data->data, provider, slen);
        data->data_len = slen;

        syslog(LOG_INFO, "adding to %s as offered service %s",
             path, acname);
        if (NgSendMsg(cs, path, NGM_PPPOE_COOKIE, NGM_PPPOE_SERVICE,
                    data, sizeof *data + slen) == -1) {
          syslog(LOG_INFO, "%s: Cannot add service on netgraph node: %m", path);
          _exit(EX_OSERR);
        }
      }

      /* Put the peer's MAC address in the environment */
      if (sz >= sizeof(struct ether_header)) {
        macaddr = ((struct ether_header *)request)->ether_shost;
        snprintf(env, sizeof(env), "%x:%x:%x:%x:%x:%x",
                 macaddr[0], macaddr[1], macaddr[2], macaddr[3], macaddr[4],
                 macaddr[5]);
        if (setenv(HISMACADDR, env, 1) != 0)
          syslog(LOG_INFO, "setenv: cannot set %s: %m", HISMACADDR);
      }

      /* And send our request data to the waiting node */
      if (debug)
        syslog(LOG_INFO, "Sending original request to %s (%d bytes)", path, sz);
      if (NgSendData(ds, ngc.ourhook, request, sz) == -1) {
        syslog(LOG_ERR, "Cannot send original request to %s: %m", path);
        _exit(EX_OSERR);
      }

      /* Then wait for a success indication */

      if (debug)
        syslog(LOG_INFO, "Waiting for a SUCCESS reply %s", path);

      do {
        if ((ret = NgRecvMsg(cs, rep, sizeof msgbuf, NULL)) < 0) {
          syslog(LOG_ERR, "%s: Cannot receive a message: %m", path);
          _exit(EX_OSERR);
        }

        if (ret == 0) {
          /* The socket has been closed */
          syslog(LOG_INFO, "%s: Client timed out", path);
          _exit(EX_TEMPFAIL);
        }

        if (rep->header.version != NG_VERSION) {
          syslog(LOG_ERR, "%ld: Unexpected netgraph version, expected %ld",
                 (long)rep->header.version, (long)NG_VERSION);
          _exit(EX_PROTOCOL);
        }

        if (rep->header.typecookie != NGM_PPPOE_COOKIE) {
          syslog(LOG_INFO, "%ld: Unexpected netgraph cookie, expected %ld",
                 (long)rep->header.typecookie, (long)NGM_PPPOE_COOKIE);
          continue;
        }

        switch (rep->header.cmd) {
          case NGM_PPPOE_SET_FLAG:	msg = "SET_FLAG";	break;
          case NGM_PPPOE_CONNECT:	msg = "CONNECT";	break;
          case NGM_PPPOE_LISTEN:	msg = "LISTEN";		break;
          case NGM_PPPOE_OFFER:		msg = "OFFER";		break;
          case NGM_PPPOE_SUCCESS:	msg = "SUCCESS";	break;
          case NGM_PPPOE_FAIL:		msg = "FAIL";		break;
          case NGM_PPPOE_CLOSE:		msg = "CLOSE";		break;
          case NGM_PPPOE_GET_STATUS:	msg = "GET_STATUS";	break;
          case NGM_PPPOE_ACNAME:
            msg = "ACNAME";
            if (setenv("ACNAME", sts->hook, 1) != 0)
              syslog(LOG_WARNING, "setenv: cannot set ACNAME=%s: %m",
                     sts->hook);
            break;
          case NGM_PPPOE_SESSIONID:
            msg = "SESSIONID";
            snprintf(sessionid, sizeof sessionid, "%04x", *(u_int16_t *)sts);
            if (setenv("SESSIONID", sessionid, 1) != 0)
              syslog(LOG_WARNING, "setenv: cannot set SESSIONID=%s: %m",
                     sessionid);
            break;
          default:
            snprintf(unknown, sizeof unknown, "<%d>", (int)rep->header.cmd);
            msg = unknown;
            break;
        }

        switch (rep->header.cmd) {
          case NGM_PPPOE_FAIL:
          case NGM_PPPOE_CLOSE:
            syslog(LOG_ERR, "Received NGM_PPPOE_%s (hook \"%s\")",
                   msg, sts->hook);
            _exit(0);
        }

        syslog(LOG_INFO, "Received NGM_PPPOE_%s (hook \"%s\")", msg, sts->hook);
      } while (rep->header.cmd != NGM_PPPOE_SUCCESS);

      dup2(ds, STDIN_FILENO);
      dup2(ds, STDOUT_FILENO);
      close(ds);
      close(cs);

      setsid();
      syslog(LOG_INFO, "Executing: %s", exec);
      execlp(_PATH_BSHELL, _PATH_BSHELL, "-c", exec, (char *)NULL);
      syslog(LOG_ERR, "execlp failed: %m");
      _exit(EX_OSFILE);

    default:
      wait(&ret);
      errno = ret;
      if (errno)
        syslog(LOG_ERR, "Second fork failed: %m");
      break;
  }
}
예제 #14
0
/*
 * Display a negraph message
 */
void
_NgDebugMsg(const struct ng_mesg *msg, const char *path)
{
	u_char buf[2 * sizeof(struct ng_mesg) + ARGS_BUFSIZE];
	struct ng_mesg *const req = (struct ng_mesg *)buf;
	struct ng_mesg *const bin = (struct ng_mesg *)req->data;
	int arglen, csock = -1;

	/* Display header stuff */
	NGLOGX("NG_MESG :");
	NGLOGX("  vers   %d", msg->header.version);
	NGLOGX("  arglen %d", msg->header.arglen);
	NGLOGX("  flags  %u", msg->header.flags);
	NGLOGX("  token  %u", msg->header.token);
	NGLOGX("  cookie %s (%d)",
	    NgCookie(msg->header.typecookie), msg->header.typecookie);

	/* At lower debugging levels, skip ASCII translation */
	if (_gNgDebugLevel <= 2)
		goto fail2;

	/* If path is not absolute, don't bother trying to use relative
	   address on a different socket for the ASCII translation */
	if (strchr(path, ':') == NULL)
		goto fail2;

	/* Get a temporary socket */
	if (NgMkSockNode(NULL, &csock, NULL) < 0)
		goto fail;

	/* Copy binary message into request message payload */
	arglen = msg->header.arglen;
	if (arglen > ARGS_BUFSIZE)
		arglen = ARGS_BUFSIZE;
	memcpy(bin, msg, sizeof(*msg) + arglen);
	bin->header.arglen = arglen;

	/* Lower debugging to avoid infinite recursion */
	_gNgDebugLevel -= RECURSIVE_DEBUG_ADJUST;

	/* Ask the node to translate the binary message to ASCII for us */
	if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
	    NGM_BINARY2ASCII, bin, sizeof(*bin) + bin->header.arglen) < 0) {
		_gNgDebugLevel += RECURSIVE_DEBUG_ADJUST;
		goto fail;
	}
	if (NgRecvMsg(csock, req, sizeof(buf), NULL) < 0) {
		_gNgDebugLevel += RECURSIVE_DEBUG_ADJUST;
		goto fail;
	}

	/* Restore debugging level */
	_gNgDebugLevel += RECURSIVE_DEBUG_ADJUST;

	/* Display command string and arguments */
	NGLOGX("  cmd    %s (%d)", bin->header.cmdstr, bin->header.cmd);
	NGLOGX("  args   %s", bin->data);
	goto done;

fail:
	/* Just display binary version */
	NGLOGX("  [error decoding message: %s]", strerror(errno));
fail2:
	NGLOGX("  cmd    %d", msg->header.cmd);
	NGLOGX("  args (%d bytes)", msg->header.arglen);
	_NgDebugBytes(msg->data, msg->header.arglen);

done:
	if (csock != -1)
		(void)close(csock);
}
예제 #15
0
struct device *
ether_Create(struct physical *p)
{
  u_char rbuf[2048];
  struct etherdevice *dev;
  struct ng_mesg *resp;
  const struct hooklist *hlist;
  const struct nodeinfo *ninfo;
  char *path, *sessionid;
  const char *mode;
  size_t ifacelen;
  unsigned f;

  dev = NULL;
  path = NULL;
  ifacelen = 0;
  if (p->fd < 0 && !strncasecmp(p->name.full, NG_PPPOE_NODE_TYPE,
                                PPPOE_NODE_TYPE_LEN) &&
      p->name.full[PPPOE_NODE_TYPE_LEN] == ':') {
    const struct linkinfo *nlink;
    struct ngpppoe_init_data *data;
    struct ngm_mkpeer mkp;
    struct ngm_connect ngc;
    const char *iface, *provider;
    char etherid[12];
    int providerlen;
    char connectpath[sizeof dev->hook + 2];	/* .:<hook> */

    p->fd--;				/* We own the device - change fd */

    loadmodules(LOAD_VERBOSLY, "netgraph", "ng_ether", "ng_pppoe", "ng_socket",
                NULL);

    if ((dev = malloc(sizeof *dev)) == NULL)
      return NULL;

    iface = p->name.full + PPPOE_NODE_TYPE_LEN + 1;

    provider = strchr(iface, ':');
    if (provider) {
      ifacelen = provider - iface;
      provider++;
      providerlen = strlen(provider);
    } else {
      ifacelen = strlen(iface);
      provider = "";
      providerlen = 0;
    }

    /*
     * We're going to do this (where tunN is our tunnel device):
     *
     * .---------.
     * |  ether  |
     * | <iface> |                         dev->cs
     * `---------'                           |
     *  (orphan)                     p->fd   |
     *     |                           |     |
     *     |                           |     |
     * (ethernet)                      |     |
     * .---------.                  .-----------.
     * |  pppoe  |                  |  socket   |
     * | <iface> |(tunN)<---->(tunN)| <unnamed> |
     * `---------                   `-----------'
     *   (tunX)
     *     ^
     *     |
     *     `--->(tunX)
     */

    /* Create a socket node */
    if (ID0NgMkSockNode(NULL, &dev->cs, &p->fd) == -1) {
      log_Printf(LogWARN, "Cannot create netgraph socket node: %s\n",
                 strerror(errno));
      free(dev);
      p->fd = -2;
      return NULL;
    }

    /*
     * Ask for a list of hooks attached to the "ether" node.  This node should
     * magically exist as a way of hooking stuff onto an ethernet device
     */
    path = (char *)alloca(ifacelen + 2);
    sprintf(path, "%.*s:", (int)ifacelen, iface);
    if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
                  NULL, 0) < 0) {
      log_Printf(LogWARN, "%s Cannot send a netgraph message: %s\n",
                 path, strerror(errno));
      return ether_Abandon(dev, p);
    }

    /* Get our list back */
    resp = (struct ng_mesg *)rbuf;
    if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) {
      log_Printf(LogWARN, "Cannot get netgraph response: %s\n",
                 strerror(errno));
      return ether_Abandon(dev, p);
    }

    hlist = (const struct hooklist *)resp->data;
    ninfo = &hlist->nodeinfo;

    /* Make sure we've got the right type of node */
    if (strncmp(ninfo->type, NG_ETHER_NODE_TYPE,
                sizeof NG_ETHER_NODE_TYPE - 1)) {
      log_Printf(LogWARN, "%s Unexpected node type ``%s'' (wanted ``"
                 NG_ETHER_NODE_TYPE "'')\n", path, ninfo->type);
      return ether_Abandon(dev, p);
    }

    log_Printf(LogDEBUG, "List of netgraph node ``%s'' (id %x) hooks:\n",
               path, ninfo->id);

    /* look for a hook already attached.  */
    for (f = 0; f < ninfo->hooks; f++) {
      nlink = &hlist->link[f];

      log_Printf(LogDEBUG, "  Found %s -> %s\n", nlink->ourhook,
                 nlink->peerhook);

      if (!strcmp(nlink->ourhook, NG_ETHER_HOOK_ORPHAN) ||
          !strcmp(nlink->ourhook, NG_ETHER_HOOK_DIVERT)) {
        /*
         * Something is using the data coming out of this ``ether'' node.
         * If it's a PPPoE node, we use that node, otherwise we complain that
         * someone else is using the node.
         */
        if (!strcmp(nlink->nodeinfo.type, NG_PPPOE_NODE_TYPE))
          /* Use this PPPoE node ! */
          snprintf(ngc.path, sizeof ngc.path, "[%x]:", nlink->nodeinfo.id);
        else {
          log_Printf(LogWARN, "%s Node type ``%s'' is currently active\n",
                     path, nlink->nodeinfo.type);
          return ether_Abandon(dev, p);
        }
        break;
      }
    }

    if (f == ninfo->hooks) {
      /*
       * Create a new ``PPPoE'' node connected to the ``ether'' node using
       * the ``orphan'' and ``ethernet'' hooks
       */
      snprintf(mkp.type, sizeof mkp.type, "%s", NG_PPPOE_NODE_TYPE);
      snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", NG_ETHER_HOOK_ORPHAN);
      snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", NG_PPPOE_HOOK_ETHERNET);
      snprintf(etherid, sizeof etherid, "[%x]:", ninfo->id);

      log_Printf(LogDEBUG, "Creating PPPoE netgraph node %s%s -> %s\n",
                 etherid, mkp.ourhook, mkp.peerhook);

      if (NgSendMsg(dev->cs, etherid, NGM_GENERIC_COOKIE,
                    NGM_MKPEER, &mkp, sizeof mkp) < 0) {
        log_Printf(LogWARN, "%s Cannot create PPPoE netgraph node: %s\n",
                   etherid, strerror(errno));
        return ether_Abandon(dev, p);
      }

      snprintf(ngc.path, sizeof ngc.path, "%s%s", path, NG_ETHER_HOOK_ORPHAN);
    }

    snprintf(dev->hook, sizeof dev->hook, "%s%d",
             TUN_NAME, p->dl->bundle->unit);

    /*
     * Connect the PPPoE node to our socket node.
     * ngc.path has already been set up
     */
    snprintf(ngc.ourhook, sizeof ngc.ourhook, "%s", dev->hook);
    memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook);

    log_Printf(LogDEBUG, "Connecting netgraph socket .:%s -> %s:%s\n",
               ngc.ourhook, ngc.path, ngc.peerhook);
    if (NgSendMsg(dev->cs, ".:", NGM_GENERIC_COOKIE,
                  NGM_CONNECT, &ngc, sizeof ngc) < 0) {
      log_Printf(LogWARN, "Cannot connect PPPoE and socket netgraph "
                 "nodes: %s\n", strerror(errno));
      return ether_Abandon(dev, p);
    }

    /* Bring the Ethernet interface up */
    path[ifacelen] = '\0';	/* Remove the trailing ':' */
    if (!iface_SetFlags(path, IFF_UP))
      log_Printf(LogWARN, "%s: Failed to set the IFF_UP flag on %s\n",
                 p->link.name, path);

    snprintf(connectpath, sizeof connectpath, ".:%s", dev->hook);

    /* Configure node to 3Com mode if needed */
    if (p->cfg.pppoe_configured) {
      mode = p->cfg.nonstandard_pppoe ? NG_PPPOE_NONSTANDARD : NG_PPPOE_STANDARD;
      if (NgSendMsg(dev->cs, connectpath, NGM_PPPOE_COOKIE,
		NGM_PPPOE_SETMODE, mode, strlen(mode) + 1) == -1) {
        log_Printf(LogWARN, "``%s'': Cannot configure netgraph node: %s\n",
                 connectpath, strerror(errno));
        return ether_Abandon(dev, p);
      }
    }

    /* And finally, request a connection to the given provider */

    data = (struct ngpppoe_init_data *)alloca(sizeof *data + providerlen);
    snprintf(data->hook, sizeof data->hook, "%s", dev->hook);
    memcpy(data->data, provider, providerlen);
    data->data_len = providerlen;

    log_Printf(LogDEBUG, "Sending PPPOE_CONNECT to %s\n", connectpath);
    if (NgSendMsg(dev->cs, connectpath, NGM_PPPOE_COOKIE,
                  NGM_PPPOE_CONNECT, data, sizeof *data + providerlen) == -1) {
      log_Printf(LogWARN, "``%s'': Cannot start netgraph node: %s\n",
                 connectpath, strerror(errno));
      return ether_Abandon(dev, p);
    }

    /* Hook things up so that we monitor dev->cs */
    p->desc.UpdateSet = ether_UpdateSet;
    p->desc.IsSet = ether_IsSet;
    p->desc.Read = ether_DescriptorRead;

    memcpy(&dev->dev, &baseetherdevice, sizeof dev->dev);
    switch (p->cfg.cd.necessity) {
      case CD_VARIABLE:
        dev->dev.cd.delay = p->cfg.cd.delay;
        break;
      case CD_REQUIRED:
        dev->dev.cd = p->cfg.cd;
        break;
      case CD_NOTREQUIRED:
        log_Printf(LogWARN, "%s: Carrier must be set, using ``set cd %d!''\n",
                   p->link.name, dev->dev.cd.delay);
      case CD_DEFAULT:
        break;
    }

    dev->timeout = dev->dev.cd.delay;
    dev->connected = CARRIER_PENDING;
    /* This will be overridden by our session id - if provided by netgraph */
    dev->slot = GetIfIndex(path);
  } else {
    /* See if we're a netgraph socket */
    struct stat st;

    if (fstat(p->fd, &st) != -1 && (st.st_mode & S_IFSOCK)) {
      struct sockaddr_storage ssock;
      struct sockaddr *sock = (struct sockaddr *)&ssock;
      int sz;

      sz = sizeof ssock;
      if (getsockname(p->fd, sock, &sz) == -1) {
        log_Printf(LogPHASE, "%s: Link is a closed socket !\n", p->link.name);
        close(p->fd);
        p->fd = -1;
        return NULL;
      }

      if (sock->sa_family == AF_NETGRAPH) {
        /*
         * It's a netgraph node... We can't determine hook names etc, so we
         * stay pretty impartial....
         */
        log_Printf(LogPHASE, "%s: Link is a netgraph node\n", p->link.name);

        if ((dev = malloc(sizeof *dev)) == NULL) {
          log_Printf(LogWARN, "%s: Cannot allocate an ether device: %s\n",
                     p->link.name, strerror(errno));
          return NULL;
        }

        memcpy(&dev->dev, &baseetherdevice, sizeof dev->dev);
        dev->cs = -1;
        dev->timeout = 0;
        dev->connected = CARRIER_OK;
        *dev->hook = '\0';

        /*
         * If we're being envoked from pppoed(8), we may have a SESSIONID
         * set in the environment.  If so, use it as the slot
         */
        if ((sessionid = getenv("SESSIONID")) != NULL) {
          char *end;
          u_long slot;

          slot = strtoul(sessionid, &end, 16);
          dev->slot = end != sessionid && *end == '\0' ? slot : 0;
        } else
          dev->slot = 0;
      }
    }
  }

  if (dev) {
    physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF);
    return &dev->dev;
  }

  return NULL;
}
예제 #16
0
static int
ip_account_show(int v, int outgoing)
{
	struct ng_ipacct_ainfo ci;
	struct ng_ipacct_hinfo hi;
	int token, nread;
	struct ng_mesg *ng_mesg;
	struct ng_ipacct_mesg *ng_cmesg;
	struct ip_acct_chunk *data;
	char path[NG_PATHLEN + 1];

	ng_cmesg = alloca(sizeof(*ng_cmesg));
	snprintf(ng_cmesg->hname, sizeof(ng_cmesg->hname), 
	    "%s_%s", ng_hookprefix, outgoing ? "out" : "in");

	ng_mesg = alloca(REPL_SIZE);

	if (ip_account_get_info(NGM_IPACCT_CINFO, &ci, sizeof(ci), outgoing)) {
		return (-1);
	}
	if (ip_account_get_info(NGM_IPACCT_HINFO, &hi, sizeof(hi), outgoing)) {
		return (-1);
	}
	for (;;) {
		/* request set of accounting records */
		token = NgSendMsg(ng_cs, ng_nodename, NGM_IPACCT_COOKIE, 
		    NGM_IPACCT_SHOW, ng_cmesg, sizeof(*ng_cmesg));
		if (token == -1) {
			warn("NgSendMsg(NGM_IPACCT_SHOW)");
			return (-1);
		}

        /* read reply */
        if (ng_ready_for_read() != 1)
            return (-1);
        nread = NgRecvMsg(ng_cs, ng_mesg, REPL_SIZE, path);
        if (nread == -1) {
            warn("NgRecvMsg(NG_IPACCT_SHOW)");
            return (-1);
        }

		if (ng_mesg->header.token != token) {
			warnx("NgRecvMsg(NGM_IPACCT_SHOW): token mismatch");
			return (-1);
		}

		data = (struct ip_acct_chunk*)ng_mesg->data;
		if (ng_mesg->header.arglen != sizeof(*data)) {
			warnx("NgRecvMsg(NGM_IPACCT_SHOW): arglen too small");
			return (-1);
		}

		if (data->nrecs == 0)
			break; /* no more data available */
		ip_account_print(data, hi.hi_flags);
	}
	if (ci.ai_th_packets)
		printf(" Accounting exceed threshold by %u packets (%" PRIu64 " bytes)\n",
		    ci.ai_th_packets, ci.ai_th_bytes);
	
	return (0);
}
예제 #17
0
static int
ShowCmd(int ac, const char **av)
{
	const char *path;
	u_char rbuf[16 * 1024];
	struct ng_mesg *const resp = (struct ng_mesg *) rbuf;
	struct hooklist *const hlist = (struct hooklist *) resp->data;
	struct nodeinfo *const ninfo = &hlist->nodeinfo;
	int ch, no_hooks = 0;

	/* Get options */
	optind = 1;
	while ((ch = getopt(ac, __DECONST(char **, av), "n")) != -1) {
		switch (ch) {
		case 'n':
			no_hooks = 1;
			break;
		case '?':
		default:
			return(CMDRTN_USAGE);
			break;
		}
	}
	ac -= optind;
	av += optind;

	/* Get arguments */
	switch (ac) {
	case 1:
		path = av[0];
		break;
	default:
		return(CMDRTN_USAGE);
	}

	/* Get node info and hook list */
	if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
	    NGM_LISTHOOKS, NULL, 0) < 0) {
		warn("send msg");
		return(CMDRTN_ERROR);
	}
	if (NgRecvMsg(csock, resp, sizeof(rbuf), NULL) < 0) {
		warn("recv msg");
		return(CMDRTN_ERROR);
	}

	/* Show node information */
	if (!*ninfo->name)
		snprintf(ninfo->name, sizeof(ninfo->name), "%s", UNNAMED);
	printf("  Name: %-15s Type: %-15s ID: %08x   Num hooks: %d\n",
	    ninfo->name, ninfo->type, ninfo->id, ninfo->hooks);
	if (!no_hooks && ninfo->hooks > 0) {
		uint32_t k;

		printf(FMT, "Local hook", "Peer name",
		    "Peer type", "Peer ID", "Peer hook");
		printf(FMT, "----------", "---------",
		    "---------", "-------", "---------");
		for (k = 0; k < ninfo->hooks; k++) {
			struct linkinfo *const sc_link = &hlist->link[k];
			struct nodeinfo *const peer = &hlist->link[k].nodeinfo;
			char idbuf[20];

			if (!*peer->name) {
				snprintf(peer->name, sizeof(peer->name),
				  "%s", UNNAMED);
			}
			snprintf(idbuf, sizeof(idbuf), "%08x", peer->id);
			printf(FMT, sc_link->ourhook, peer->name,
			    peer->type, idbuf, sc_link->peerhook);
		}
	}
	return(CMDRTN_OK);
}
예제 #18
0
struct device *
ng_Create(struct physical *p)
{
    struct sockaddr_ng ngsock;
    u_char rbuf[2048];
    struct sockaddr *sock = (struct sockaddr *)&ngsock;
    const struct hooklist *hlist;
    const struct nodeinfo *ninfo;
    const struct linkinfo *nlink;
    struct ngdevice *dev;
    struct ng_mesg *resp;
    struct ngm_mkpeer mkp;
    struct ngm_connect ngc;
    const char *devp, *endp;
    char lasthook[NG_HOOKSIZ];
    char hook[NG_HOOKSIZ];
    char nodetype[NG_TYPESIZ + NG_NODESIZ];
    char modname[NG_TYPESIZ + 3];
    char path[NG_PATHSIZ];
    char *nodename;
    int len, sz, done;
    unsigned f;

    dev = NULL;
    if (p->fd < 0 && !strncasecmp(p->name.full, NETGRAPH_PREFIX,
                                  sizeof NETGRAPH_PREFIX - 1)) {
        p->fd--;				/* We own the device - change fd */

        if ((dev = malloc(sizeof *dev)) == NULL)
            return NULL;

        loadmodules(LOAD_VERBOSLY, "netgraph", "ng_socket", NULL);

        /* Create a socket node */
        if (ID0NgMkSockNode(NULL, &dev->cs, &p->fd) == -1) {
            log_Printf(LogWARN, "Cannot create netgraph socket node: %s\n",
                       strerror(errno));
            free(dev);
            p->fd = -2;
            return NULL;
        }

        devp = p->name.full + sizeof NETGRAPH_PREFIX - 1;
        *lasthook = *path = '\0';
        log_Printf(LogDEBUG, "%s: Opening netgraph device \"%s\"\n",
                   p->link.name, devp);
        done = 0;

        while (*devp != '\0' && !done) {
            if (*devp != '[') {
                if (*lasthook == '\0') {
                    log_Printf(LogWARN, "%s: Netgraph devices must start with"
                               " [nodetype:nodename]\n", p->link.name);
                    return ng_Abandon(dev, p);
                }

                /* Get the hook name of the new node */
                if (!GETSEGMENT(hook, devp, ".[", &endp))
                    return ng_Abandon(dev, p);
                log_Printf(LogDEBUG, "%s: Got hook \"%s\"\n", p->link.name, hook);
                devp = endp;
                if (*devp == '\0') {
                    log_Printf(LogWARN, "%s: Netgraph device must not end with a second"
                               " hook\n", p->link.name);
                    return ng_Abandon(dev, p);
                }
                if (devp[-1] != '[') {
                    log_Printf(LogWARN, "%s: Expected a [nodetype:nodename] at device"
                               " pos %d\n", p->link.name, devp - p->link.name - 1);
                    return ng_Abandon(dev, p);
                }
            } else {
                /* Use lasthook as the hook name */
                strcpy(hook, lasthook);
                devp++;
            }

            /* We've got ``lasthook'' and ``hook'', get the node type */
            if (!GETSEGMENT(nodetype, devp, "]", &endp))
                return ng_Abandon(dev, p);
            log_Printf(LogDEBUG, "%s: Got node \"%s\"\n", p->link.name, nodetype);

            if ((nodename = strchr(nodetype, ':')) != NULL) {
                *nodename++ = '\0';
                if (*nodename == '\0' && *nodetype == '\0') {
                    log_Printf(LogWARN, "%s: Empty [nodetype:nodename] at device"
                               " pos %d\n", p->link.name, devp - p->link.name - 1);
                    return ng_Abandon(dev, p);
                }
            }

            /* Ignore optional colons after nodes */
            devp = *endp == ':' ? endp + 1 : endp;
            if (*devp == '.')
                devp++;

            if (*lasthook == '\0') {
                /* This is the first node in the chain */
                if (nodename == NULL || *nodename == '\0') {
                    log_Printf(LogWARN, "%s: %s: No initial device nodename\n",
                               p->link.name, devp);
                    return ng_Abandon(dev, p);
                }

                if (*nodetype != '\0') {
                    /* Attempt to load the module */
                    snprintf(modname, sizeof modname, "ng_%s", nodetype);
                    log_Printf(LogDEBUG, "%s: Attempting to load %s.ko\n",
                               p->link.name, modname);
                    loadmodules(LOAD_QUIETLY, modname, NULL);
                }

                snprintf(path, sizeof path, "%s:", nodename);
                /* XXX: If we have a node type, ensure it's correct */
            } else {
                /*
                 * Ask for a list of hooks attached to the previous node.  If we
                 * find the one we're interested in, and if it's connected to a
                 * node of the right type using the correct hook, use that.
                 * If we find the hook connected to something else, fail.
                 * If we find no match, mkpeer the new node.
                 */
                if (*nodetype == '\0') {
                    log_Printf(LogWARN, "%s: Nodetype missing at device offset %d\n",
                               p->link.name,
                               devp - p->name.full + sizeof NETGRAPH_PREFIX - 1);
                    return ng_Abandon(dev, p);
                }

                /* Get a list of node hooks */
                if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
                              NULL, 0) < 0) {
                    log_Printf(LogWARN, "%s: %s Cannot send a LISTHOOOKS message: %s\n",
                               p->link.name, path, strerror(errno));
                    return ng_Abandon(dev, p);
                }

                /* Get our list back */
                resp = (struct ng_mesg *)rbuf;
                if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) {
                    log_Printf(LogWARN, "%s: Cannot get netgraph response: %s\n",
                               p->link.name, strerror(errno));
                    return ng_Abandon(dev, p);
                }

                hlist = (const struct hooklist *)resp->data;
                ninfo = &hlist->nodeinfo;

                log_Printf(LogDEBUG, "List of netgraph node ``%s'' (id %x) hooks:\n",
                           path, ninfo->id);

                /* look for a hook already attached.  */
                for (f = 0; f < ninfo->hooks; f++) {
                    nlink = &hlist->link[f];

                    log_Printf(LogDEBUG, "  Found %s -> %s (type %s)\n", nlink->ourhook,
                               nlink->peerhook, nlink->nodeinfo.type);

                    if (!strcmp(nlink->ourhook, lasthook)) {
                        if (strcmp(nlink->peerhook, hook) ||
                                strcmp(nlink->nodeinfo.type, nodetype)) {
                            log_Printf(LogWARN, "%s: hook %s:%s is already in use\n",
                                       p->link.name, nlink->ourhook, path);
                            return ng_Abandon(dev, p);
                        }
                        /* The node is already hooked up nicely.... reuse it */
                        break;
                    }
                }

                if (f == ninfo->hooks) {
                    /* Attempt to load the module */
                    snprintf(modname, sizeof modname, "ng_%s", nodetype);
                    log_Printf(LogDEBUG, "%s: Attempting to load %s.ko\n",
                               p->link.name, modname);
                    loadmodules(LOAD_QUIETLY, modname, NULL);

                    /* Create (mkpeer) the new node */

                    snprintf(mkp.type, sizeof mkp.type, "%s", nodetype);
                    snprintf(mkp.ourhook, sizeof mkp.ourhook, "%s", lasthook);
                    snprintf(mkp.peerhook, sizeof mkp.peerhook, "%s", hook);

                    log_Printf(LogDEBUG, "%s: Doing MKPEER %s%s -> %s (type %s)\n",
                               p->link.name, path, mkp.ourhook, mkp.peerhook, nodetype);

                    if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE,
                                  NGM_MKPEER, &mkp, sizeof mkp) < 0) {
                        log_Printf(LogWARN, "%s Cannot create %s netgraph node: %s\n",
                                   path, nodetype, strerror(errno));
                        return ng_Abandon(dev, p);
                    }
                }
                len = strlen(path);
                snprintf(path + len, sizeof path - len, "%s%s",
                         path[len - 1] == ':' ? "" : ".", lasthook);
            }

            /* Get a list of node hooks */
            if (NgSendMsg(dev->cs, path, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
                          NULL, 0) < 0) {
                log_Printf(LogWARN, "%s: %s Cannot send a LISTHOOOKS message: %s\n",
                           p->link.name, path, strerror(errno));
                return ng_Abandon(dev, p);
            }

            /* Get our list back */
            resp = (struct ng_mesg *)rbuf;
            if (NgRecvMsg(dev->cs, resp, sizeof rbuf, NULL) <= 0) {
                log_Printf(LogWARN, "%s: Cannot get netgraph response: %s\n",
                           p->link.name, strerror(errno));
                return ng_Abandon(dev, p);
            }

            hlist = (const struct hooklist *)resp->data;
            ninfo = &hlist->nodeinfo;

            if (*lasthook != '\0' && nodename != NULL && *nodename != '\0' &&
                    strcmp(ninfo->name, nodename) &&
                    NgNameNode(dev->cs, path, "%s", nodename) < 0) {
                log_Printf(LogWARN, "%s: %s: Cannot name netgraph node: %s\n",
                           p->link.name, path, strerror(errno));
                return ng_Abandon(dev, p);
            }

            if (!GETSEGMENT(lasthook, devp, " \t.[", &endp))
                return ng_Abandon(dev, p);
            log_Printf(LogDEBUG, "%s: Got hook \"%s\"\n", p->link.name, lasthook);

            len = strlen(lasthook);
            done = strchr(" \t", devp[len]) ? 1 : 0;
            devp = endp;

            if (*devp != '\0') {
                if (devp[-1] == '[')
                    devp--;
            } /* else should moan about devp[-1] being '[' ? */
        }

        snprintf(dev->hook, sizeof dev->hook, "%s", lasthook);

        /* Connect the node to our socket node */
        snprintf(ngc.path, sizeof ngc.path, "%s", path);
        snprintf(ngc.ourhook, sizeof ngc.ourhook, "%s", dev->hook);
        memcpy(ngc.peerhook, ngc.ourhook, sizeof ngc.peerhook);

        log_Printf(LogDEBUG, "Connecting netgraph socket .:%s -> %s.%s\n",
                   ngc.ourhook, ngc.path, ngc.peerhook);
        if (NgSendMsg(dev->cs, ".:", NGM_GENERIC_COOKIE,
                      NGM_CONNECT, &ngc, sizeof ngc) < 0) {
            log_Printf(LogWARN, "Cannot connect %s and socket netgraph "
                       "nodes: %s\n", path, strerror(errno));
            return ng_Abandon(dev, p);
        }

        /* Hook things up so that we monitor dev->cs */
        p->desc.UpdateSet = ng_UpdateSet;
        p->desc.IsSet = ng_IsSet;
        p->desc.Read = ng_DescriptorRead;

        memcpy(&dev->dev, &basengdevice, sizeof dev->dev);

    } else {
        /* See if we're a netgraph socket */

        sz = sizeof ngsock;
        if (getsockname(p->fd, sock, &sz) != -1 && sock->sa_family == AF_NETGRAPH) {
            /*
             * It's a netgraph node... We can't determine hook names etc, so we
             * stay pretty impartial....
             */
            log_Printf(LogPHASE, "%s: Link is a netgraph node\n", p->link.name);

            if ((dev = malloc(sizeof *dev)) == NULL) {
                log_Printf(LogWARN, "%s: Cannot allocate an ether device: %s\n",
                           p->link.name, strerror(errno));
                return NULL;
            }

            memcpy(&dev->dev, &basengdevice, sizeof dev->dev);
            dev->cs = -1;
            *dev->hook = '\0';
        }
    }

    if (dev) {
        physical_SetupStack(p, dev->dev.name, PHYSICAL_FORCE_SYNCNOACF);
        return &dev->dev;
    }

    return NULL;
}