Beispiel #1
0
static void start_server(const char *host, int port)
{
  struct sockaddr_in addr;

	serv_hnd.fd = socket(PF_INET, SOCK_STREAM, 0);
  if (serv_hnd.fd < 0) {
    log_emerg("cli: tcp: failed to create server socket: %s\n", strerror(errno));
    return;
  }

	fcntl(serv_hnd.fd, F_SETFD, fcntl(serv_hnd.fd, F_GETFD) | FD_CLOEXEC);

	memset(&addr, 0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
	if (host)
		addr.sin_addr.s_addr = inet_addr(host);
	else
		addr.sin_addr.s_addr = htonl(INADDR_ANY);

  setsockopt(serv_hnd.fd, SOL_SOCKET, SO_REUSEADDR, &serv_hnd.fd, 4);
  if (bind (serv_hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
    log_emerg("cli: tcp: failed to bind socket: %s\n", strerror(errno));
		close(serv_hnd.fd);
    return;
	}

  if (listen (serv_hnd.fd, 1) < 0) {
    log_emerg("cli: tcp: failed to listen socket: %s\n", strerror(errno));
		close(serv_hnd.fd);
    return;
  }

	if (fcntl(serv_hnd.fd, F_SETFL, O_NONBLOCK)) {
    log_emerg("cli: tcp: failed to set nonblocking mode: %s\n", strerror(errno));
		close(serv_hnd.fd);
    return;
	}

  addr.sin_family = AF_INET;
  addr.sin_port = htons(port);
	addr.sin_addr.s_addr = inet_addr(host);

	triton_context_register(&serv_ctx, NULL);
	triton_context_set_priority(&serv_ctx, 1);
	triton_md_register_handler(&serv_ctx, &serv_hnd);
	triton_md_enable_handler(&serv_hnd, MD_MODE_READ);
	triton_context_wakeup(&serv_ctx);
}
void ipoe_nl_get_sessions(struct list_head *list)
{
	struct nlmsghdr *nlh;
	struct genlmsghdr *ghdr;
	struct {
		struct nlmsghdr n;
		char buf[1024];
	} req;

	if (rth.fd == -1)
		return;

	nlh = &req.n;
	nlh->nlmsg_len = NLMSG_LENGTH(GENL_HDRLEN);
	nlh->nlmsg_flags = NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST;
	nlh->nlmsg_type = ipoe_genl_id;
	nlh->nlmsg_seq = rth.dump = ++rth.seq;

	ghdr = NLMSG_DATA(&req.n);
	ghdr->cmd = IPOE_CMD_GET;

	if (rtnl_send(&rth, (char *)nlh, nlh->nlmsg_len) < 0) {
		log_emerg("ipoe: failed to send dump request: %s\n", strerror(errno));
		return;
	}

	rtnl_dump_filter(&rth, dump_session, list, NULL, NULL);
}
Beispiel #3
0
static void init(void)
{
	const char *opt;
	char *host, *d;
	int port;

	opt = conf_get_opt("cli", "tcp");
	if (!opt)
		return;

	host = strdup(opt);
	d = strstr(host, ":");
	if (!d)
		goto err_fmt;

	*d = 0;
	port = atoi(d + 1);
	if (port <= 0)
		goto err_fmt;

	load_config();

	temp_buf = malloc(RECV_BUF_SIZE);

	start_server(host, port);

	triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);

	return;
err_fmt:
	log_emerg("cli: tcp: invalid format\n");
	free(host);
}
Beispiel #4
0
static void*
thread_run(void *vparam)
{
    logc_t *lg = (logc_t*)vparam;

    while (g_thread_run) {

        if (log_info(lg, "info testing\n") == 0) {
            printf("client: info error !\n");
            break;
        }

        if (log_debug(lg, "debug testing\n") == 0) {
            printf("client: debug error !\n");
            break;
        }

        if (log_emerg(lg, "emerg testing\n") == 0) {
            printf("client: emerg error !\n");
            break;
        }
    }

    pthread_exit(NULL);
}
Beispiel #5
0
static void load_config(void)
{
	char *opt;

	opt = conf_get_opt("ppp", "mtu");
	if (opt && atoi(opt) > 0)
		conf_mtu = atoi(opt);

	opt = conf_get_opt("ppp", "mru");
	if (opt && atoi(opt) > 0)
		conf_mru = atoi(opt);

	opt = conf_get_opt("ppp", "min-mtu");
	if (opt && atoi(opt) > 0)
		conf_min_mtu = atoi(opt);

	opt = conf_get_opt("ppp", "max-mtu");
	if (opt && atoi(opt) > 0)
		conf_max_mtu = atoi(opt);

	if (conf_mru && conf_min_mtu > conf_mru) {
		log_emerg("min-mtu cann't be greater then mtu/mru\n");
		conf_min_mtu = conf_mru;
	}
}
Beispiel #6
0
static int agent_log(int major, int minor, void *serv_arg, void *cl_arg)
{
	struct snmp_log_message *m = serv_arg;

	switch (m->priority) {
		case LOG_EMERG:
			log_emerg("net-snmp: %s", m->msg);
			break;
		case LOG_ALERT:
		case LOG_CRIT:
		case LOG_ERR:
			log_error("net-snmp: %s", m->msg);
			break;
		case LOG_WARNING:
			log_warn("net-snmp: %s", m->msg);
			break;
		case LOG_NOTICE:
			log_info1("net-snmp: %s", m->msg);
			break;
		case LOG_INFO:
			log_info2("net-snmp: %s", m->msg);
			break;
		case LOG_DEBUG:
			log_debug("net-snmp: %s", m->msg);
			break;
		default:
			log_msg("net-snmp: %s", m->msg);
	}
	return 0;
}
Beispiel #7
0
static
int ugh_command_import(ugh_config_t *cfg, int argc, char **argv, ugh_command_t *cmd)
{
	char name [1024];
	char pbuf [PATH_MAX], *path;

	snprintf(name, 1024, "ugh_module_%s", argv[1]);

	if (2 < argc)
	{
		path = argv[2];
	}
	else
	{
		snprintf(pbuf, PATH_MAX, UGH_MODULE_PREFIX "%s" UGH_MODULE_SUFFIX, argv[1]);
		path = pbuf;
	}

	void *handle = dlopen(path, RTLD_NOW);

	if (NULL == handle)
	{
		log_emerg("dlopen(%s, RTLD_NOW): %s", path, dlerror());
		return -1;
	}

	char *dl_err = dlerror(); /* clear error before calling dlsym() */

	ugh_module_t *module = (ugh_module_t *) dlsym(handle, name);

	if (NULL != (dl_err = dlerror()))
	{
		log_emerg("dl_err = %s", dl_err);
		return -1;
	}

	ugh_module_add(module);

	return 0;
}
static int dump_session(const struct sockaddr_nl *addr, struct nlmsghdr *n, void *arg)
{
	struct list_head *list = arg;
	struct ipoe_session_info *info;
	struct rtattr *tb[IPOE_ATTR_MAX + 1];
	struct genlmsghdr *ghdr = NLMSG_DATA(n);
	int len = n->nlmsg_len;
	struct rtattr *attrs;

	if (ghdr->cmd != IPOE_CMD_GET) {
		log_error("ipoe: dump_session: got unexpected command %d\n", ghdr->cmd);
		return 0;
	}

	len -= NLMSG_LENGTH(GENL_HDRLEN);
	if (len < 0 ) {
		log_error("ipoe: dump_session: wrong message length %i\n", len);
		return -1;
	}

	attrs = (struct rtattr *)((char *)ghdr + GENL_HDRLEN);
	parse_rtattr(tb, IPOE_ATTR_MAX, attrs, len);

	info = _malloc(sizeof(*info));
	if (!info) {
		log_emerg("out of memory\n");
		return -1;
	}

	memset(info, 0, sizeof(*info));

	if (tb[IPOE_ATTR_IFINDEX])
		info->ifindex = *(uint32_t *)(RTA_DATA(tb[IPOE_ATTR_IFINDEX]));
	else {
		log_error("ipoe: dump_session: IPOE_ATTR_IFINDEX is absent\n");
		_free(info);
		return 0;
	}

	if (tb[IPOE_ATTR_ADDR])
		info->addr = *(uint32_t *)(RTA_DATA(tb[IPOE_ATTR_ADDR]));

	if (tb[IPOE_ATTR_PEER_ADDR])
		info->peer_addr = *(uint32_t *)(RTA_DATA(tb[IPOE_ATTR_PEER_ADDR]));

	list_add_tail(&info->entry, list);

	return 0;
}
Beispiel #9
0
static void change_limits(void)
{
	FILE *f;
	struct rlimit lim;
	unsigned int nr_open = 1024*1024;

	f = fopen("/proc/sys/fs/nr_open", "r");
	if (f) {
		fscanf(f, "%d", &nr_open);
		fclose(f);
	}

	lim.rlim_cur = nr_open;
	lim.rlim_max = nr_open;
	if (setrlimit(RLIMIT_NOFILE, &lim))
		log_emerg("main: setrlimit: %s\n", strerror(errno));
}
Beispiel #10
0
int main(int argc, char **argv)
{
//	if (fork()) exit(0);
	myPID = getpid();
	log_thread_name_set("WZ");

	try
	{
		while (!doQuit)
		{
			cfg = new wzconfig();
			wz_prefork_init(argc, argv);

			if (doFork)
			{
				if (fork()) exit(0);
				myPID = getpid();
			}

			wz_postfork_init();
			log_notice("init ok, starting work");

			doRestart = 0;
			wz_work();
			wz_shutdown();
			delete cfg;
		}
	}
	catch (const std::exception& e)
	{
		log_emerg("Fatal exception: %s", e.what());
	}

	log_notice("wz-httpd stop.");
	return 0;
}
Beispiel #11
0
static void chap_send_failure(struct chap_auth_data_t *ad)
{
    struct chap_failure_t msg = {
        .hdr.proto = htons(PPP_CHAP),
        .hdr.code = CHAP_FAILURE,
        .hdr.id = ad->id,
        .hdr.len = htons(sizeof(msg) - 1 - 2),
        .message = MSG_FAILURE,
    };

    if (conf_ppp_verbose)
        log_ppp_info2("send [CHAP Failure id=%x \"%s\"]\n", msg.hdr.id, MSG_FAILURE);

    ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2);
}

static void chap_send_success(struct chap_auth_data_t *ad)
{
    struct chap_success_t msg =	{
        .hdr.proto = htons(PPP_CHAP),
        .hdr.code = CHAP_SUCCESS,
        .hdr.id = ad->id,
        .hdr.len = htons(sizeof(msg)-1-2),
        .message = MSG_SUCCESS,
    };

    if (conf_ppp_verbose)
        log_ppp_info2("send [CHAP Success id=%x \"%s\"]\n", msg.hdr.id, MSG_SUCCESS);

    ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2);
}

static void chap_send_challenge(struct chap_auth_data_t *ad)
{
    struct chap_challenge_t msg =	{
        .hdr.proto = htons(PPP_CHAP),
        .hdr.code = CHAP_CHALLENGE,
        .hdr.id = ++ad->id,
        .hdr.len = htons(sizeof(msg) - 2),
        .val_size = VALUE_SIZE,
    };

    read(urandom_fd, ad->val, VALUE_SIZE);
    memcpy(msg.val, ad->val, VALUE_SIZE);

    if (conf_ppp_verbose) {
        log_ppp_info2("send [CHAP Challenge id=%x <", msg.hdr.id);
        print_buf(msg.val, VALUE_SIZE);
        log_ppp_info2(">]\n");
    }

    ppp_chan_send(ad->ppp, &msg, ntohs(msg.hdr.len) + 2);

    if (conf_timeout && !ad->timeout.tpd)
        triton_timer_add(ad->ppp->ctrl->ctx, &ad->timeout, 0);
}

static void chap_recv_response(struct chap_auth_data_t *ad, struct chap_hdr_t *hdr)
{
    MD5_CTX md5_ctx;
    uint8_t md5[MD5_DIGEST_LENGTH];
    char *passwd;
    char *name;
    int r;
    struct chap_challenge_t *msg = (struct chap_challenge_t*)hdr;

    if (ad->timeout.tpd)
        triton_timer_del(&ad->timeout);

    if (conf_ppp_verbose) {
        log_ppp_info2("recv [CHAP Response id=%x <", msg->hdr.id);
        print_buf(msg->val, msg->val_size);
        log_ppp_info2(">, name=\"");
        print_str(msg->name, ntohs(msg->hdr.len) - sizeof(*msg) + 2);
        log_ppp_info2("\"]\n");
    }

    if (msg->hdr.id != ad->id) {
        if (conf_ppp_verbose)
            log_ppp_warn("chap-md5: id mismatch\n");
        return;
    }

    if (msg->val_size != VALUE_SIZE) {
        log_ppp_error("chap-md5: incorrect value-size (%i)\n", msg->val_size);
        chap_send_failure(ad);
        if (ad->started)
            ppp_terminate(ad->ppp, TERM_USER_ERROR, 0);
        else
            ppp_auth_failed(ad->ppp, NULL);
        return;
    }

    name = _strndup(msg->name,ntohs(msg->hdr.len) - sizeof(*msg) + 2);

    if (conf_any_login) {
        if (ppp_auth_successed(ad->ppp, name)) {
            chap_send_failure(ad);
            ppp_terminate(ad->ppp, TERM_AUTH_ERROR, 0);
            _free(name);
            return;
        }
        chap_send_success(ad);
        ad->started = 1;
        return;
    }

    r = pwdb_check(ad->ppp, name, PPP_CHAP, CHAP_MD5, ad->id, ad->val, VALUE_SIZE, msg->val);

    if (r == PWDB_NO_IMPL) {
        passwd = pwdb_get_passwd(ad->ppp,name);
        if (!passwd)
        {
            _free(name);
            if (conf_ppp_verbose)
                log_ppp_warn("chap-md5: user not found\n");
            chap_send_failure(ad);
            return;
        }

        MD5_Init(&md5_ctx);
        MD5_Update(&md5_ctx,&msg->hdr.id,1);
        MD5_Update(&md5_ctx,passwd,strlen(passwd));
        MD5_Update(&md5_ctx,ad->val,VALUE_SIZE);
        MD5_Final(md5,&md5_ctx);

        if (memcmp(md5,msg->val,sizeof(md5)))
        {
            if (conf_ppp_verbose)
                log_ppp_warn("chap-md5: challenge response mismatch\n");
            chap_send_failure(ad);
            if (ad->started)
                ppp_terminate(ad->ppp, TERM_USER_ERROR, 0);
            else
                ppp_auth_failed(ad->ppp, name);
            _free(name);
        } else {
            if (!ad->started) {
                if (ppp_auth_successed(ad->ppp, name)) {
                    chap_send_failure(ad);
                    ppp_terminate(ad->ppp, TERM_AUTH_ERROR, 0);
                    _free(name);
                } else {
                    chap_send_success(ad);
                    ad->started = 1;
                    if (conf_interval)
                        triton_timer_add(ad->ppp->ctrl->ctx, &ad->interval, 0);
                }
            } else
                _free(name);
        }
        _free(passwd);
    } else if (r == PWDB_DENIED) {
        chap_send_failure(ad);
        if (ad->started)
            ppp_terminate(ad->ppp, TERM_USER_ERROR, 0);
        else
            ppp_auth_failed(ad->ppp, name);
        _free(name);
    } else {
        if (!ad->started) {
            if (ppp_auth_successed(ad->ppp, name)) {
                chap_send_failure(ad);
                ppp_terminate(ad->ppp, TERM_AUTH_ERROR, 0);
                _free(name);
            } else {
                chap_send_success(ad);
                ad->started = 1;
                if (conf_interval)
                    triton_timer_add(ad->ppp->ctrl->ctx, &ad->interval, 0);
            }
        } else {
            chap_send_success(ad);
            _free(name);
        }
    }
}

static int chap_check(uint8_t *ptr)
{
    return *ptr == CHAP_MD5;
}

static int chap_restart(struct ppp_t *ppp, struct auth_data_t *auth)
{
    struct chap_auth_data_t *d = container_of(auth, typeof(*d), auth);

    chap_send_challenge(d);

    return 0;
}

static struct ppp_auth_handler_t chap=
{
    .name          = "CHAP-md5",
    .init          = auth_data_init,
    .free          = auth_data_free,
    .send_conf_req = lcp_send_conf_req,
    .recv_conf_req = lcp_recv_conf_req,
    .start         = chap_start,
    .finish        = chap_finish,
    .check         = chap_check,
    .restart       = chap_restart,
};

static void chap_recv(struct ppp_handler_t *h)
{
    struct chap_auth_data_t *d = container_of(h, typeof(*d), h);
    struct chap_hdr_t *hdr = (struct chap_hdr_t *)d->ppp->buf;

    if (d->ppp->buf_size < sizeof(*hdr) || ntohs(hdr->len) < HDR_LEN || ntohs(hdr->len) < d->ppp->buf_size - 2)	{
        log_ppp_warn("chap-md5: short packet received\n");
        return;
    }

    if (hdr->code == CHAP_RESPONSE)
        chap_recv_response(d, hdr);
    else
        log_ppp_warn("chap-md5: unknown code received %x\n", hdr->code);
}

static void load_config(void)
{
    const char *opt;

    opt = conf_get_opt("auth", "timeout");
    if (opt && atoi(opt) > 0)
        conf_timeout = atoi(opt);

    opt = conf_get_opt("auth", "interval");
    if (opt && atoi(opt) > 0)
        conf_interval = atoi(opt);

    opt = conf_get_opt("auth", "max-failure");
    if (opt && atoi(opt) > 0)
        conf_max_failure = atoi(opt);

    opt = conf_get_opt("auth", "any-login");
    if (opt)
        conf_any_login = atoi(opt);
}

static void auth_chap_md5_init()
{
    load_config();

    if (ppp_auth_register_handler(&chap))
        log_emerg("chap-md5: failed to register handler\n");

    triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
}

DEFINE_INIT(4, auth_chap_md5_init);
Beispiel #12
0
int main(int argc, char * const *argv) {
  uint32_t client_opts, send_level;
  const char *identity, *facility;
  
  // ASL client options
  client_opts = 0;
  
  // What level of messages are sent to syslogd
  send_level = ASL_LEVEL_NOTICE;
  
  // Sender identity. This should be NULL, as asl_open() will set this to the
  // name of the program. Only set this if you really need to.
  identity = NULL;
  
  // This should be your UTI
  facility = "se.hunch.asl.example";
  
  // Options accepted by our example program
  int ch;
  static struct option longopts[] = {
    { "debug", no_argument, NULL, 'd' },
    { "stderr", no_argument, NULL, 's' },
    { "no-remote", no_argument, NULL, 'n' },
    { "help", no_argument, NULL, 'h' },
    { NULL, 0, NULL, '\0' }
  };
  
  // Parse options
  while ((ch = getopt_long(argc, argv, "dsnh", longopts, NULL)) != -1) switch (ch) {
    
    case 'd':
      // Send all messages
      send_level = ASL_LEVEL_DEBUG;
      // This disables the remote-control mechanism for adjusting
      // filter levers for processes using e.g. syslog -c ...
      client_opts |= ASL_OPT_NO_REMOTE;
      break;
    
    case 's':
      // Print messages to stderr (adds stderr as an output file descriptor)
      client_opts |= ASL_OPT_STDERR;
      break;
    
    case 'n':
      // Send no messages at all. This does only affect what messages are sent
      // to the server and does not restrict which message are printed to
      // stderr, if enabled.
      send_level = -1;
      break;
    
    // Print usage and help
    default:
      usage(argv[0]);
      exit(1);
  }
  argc -= optind;
  argv += optind;
  
  // Setting ASL_OPT_NO_DELAY connects to the server immediately when calling asl_open()
  client_opts |= ASL_OPT_NO_DELAY;
  
  // Open connection to ASL (log_asl_client is defined in logging.h)
  // See /usr/include/asl.h for more details.
  log_asl_client = asl_open(identity, facility, client_opts);
  // The log_asl_client variable is used by the log_* and Log_* macros in logging.h
  
  // Handle errors from asl_open()
  if (log_asl_client == NULL) {
    perror("asl_open");
    exit(2);
  }
  
  // Set the level for which messages are sent to the server
  log_set_send_filter(send_level);
  
  // Emit one message for each level
  log_emerg("This is a emerg-level message -- this message may propagate "
            "to all TTYs and/or other user interfaces");
  log_alert("This is a alert-level message");
  log_crit("This is a crit-level message");
  log_err("This is a err-level message");
  log_warn("This is a warn-level message");
  log_notice("This is a notice-level message");
  log_info("This is a info-level message");
  log_debug("This message is a debug-level message");
  
  // Close connection to syslogd
  asl_close(log_asl_client);
  
  return 0;
}
Beispiel #13
0
static int send_pptp_start_ctrl_conn_rply(struct pptp_conn_t *conn, int res_code, int err_code)
{
	struct pptp_start_ctrl_conn msg = {
		.header = PPTP_HEADER_CTRL(PPTP_START_CTRL_CONN_RPLY),
		.version = htons(PPTP_VERSION),
		.result_code = res_code,
		.error_code = err_code,
		.framing_cap = htonl(3),
		.bearer_cap = htonl(3),
		.max_channels = htons(1),
		.firmware_rev = htons(PPTP_FIRMWARE_VERSION),
	};

	memset(msg.hostname, 0, sizeof(msg.hostname));
	strcpy((char*)msg.hostname, PPTP_HOSTNAME);

	memset(msg.vendor, 0, sizeof(msg.vendor));
	strcpy((char*)msg.vendor, PPTP_VENDOR);

	if (conf_verbose)
		log_ppp_info2("send [PPTP Start-Ctrl-Conn-Reply <Version %i> <Result %i> <Error %i> <Framing %x> <Bearer %x> <Max-Chan %i>]\n", msg.version, msg.result_code, msg.error_code, ntohl(msg.framing_cap), ntohl(msg.bearer_cap), ntohs(msg.max_channels));

	return post_msg(conn, &msg, sizeof(msg));
}

static int pptp_start_ctrl_conn_rqst(struct pptp_conn_t *conn)
{
	struct pptp_start_ctrl_conn *msg = (struct pptp_start_ctrl_conn *)conn->in_buf;

	if (conf_verbose)
		log_ppp_info2("recv [PPTP Start-Ctrl-Conn-Request <Version %i> <Framing %x> <Bearer %x> <Max-Chan %i>]\n", msg->version, ntohl(msg->framing_cap), ntohl(msg->bearer_cap), ntohs(msg->max_channels));

	if (conn->state != STATE_IDLE) {
		log_ppp_warn("unexpected PPTP_START_CTRL_CONN_RQST\n");
		if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_EXISTS, 0))
			return -1;
		return 0;
	}

	if (msg->version != htons(PPTP_VERSION)) {
		log_ppp_warn("PPTP version mismatch: expecting %x, received %s\n", PPTP_VERSION, msg->version);
		if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_PROTOCOL, 0))
			return -1;
		return 0;
	}
	/*if (!(ntohl(msg->framing_cap) & PPTP_FRAME_SYNC)) {
		log_ppp_warn("connection does not supports sync mode\n");
		if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_GE, 0))
			return -1;
		return 0;
	}*/
	if (send_pptp_start_ctrl_conn_rply(conn, PPTP_CONN_RES_SUCCESS, 0))
		return -1;

	triton_timer_mod(&conn->timeout_timer, 0);

	conn->state = STATE_ESTB;

	return 0;
}

static int send_pptp_out_call_rply(struct pptp_conn_t *conn, struct pptp_out_call_rqst *rqst, int call_id, int res_code, int err_code)
{
	struct pptp_out_call_rply msg = {
		.header = PPTP_HEADER_CTRL(PPTP_OUT_CALL_RPLY),
		.call_id = htons(call_id),
		.call_id_peer = rqst->call_id,
		.result_code = res_code,
		.error_code = err_code,
		.cause_code = 0,
		.speed = rqst->bps_max,
		.recv_size = rqst->recv_size,
		.delay = 0,
		.channel = 0,
	};

	if (conf_verbose)
		log_ppp_info2("send [PPTP Outgoing-Call-Reply <Call-ID %x> <Peer-Call-ID %x> <Result %i> <Error %i> <Cause %i> <Speed %i> <Window-Size %i> <Delay %i> <Channel %x>]\n", ntohs(msg.call_id), ntohs(msg.call_id_peer), msg.result_code, msg.error_code, ntohs(msg.cause_code), ntohl(msg.speed), ntohs(msg.recv_size), ntohs(msg.delay), ntohl(msg.channel));

	return post_msg(conn, &msg, sizeof(msg));
}

static int pptp_out_call_rqst(struct pptp_conn_t *conn)
{
	struct pptp_out_call_rqst *msg = (struct pptp_out_call_rqst *)conn->in_buf;
	struct sockaddr_pppox src_addr, dst_addr;
  struct sockaddr_in addr;
	socklen_t addrlen;
	int pptp_sock;

	if (conf_verbose)
		log_ppp_info2("recv [PPTP Outgoing-Call-Request <Call-ID %x> <Call-Serial %x> <Min-BPS %i> <Max-BPS %i> <Bearer %x> <Framing %x> <Window-Size %i> <Delay %i>]\n", ntohs(msg->call_id), ntohs(msg->call_sernum), ntohl(msg->bps_min), ntohl(msg->bps_max), ntohl(msg->bearer), ntohl(msg->framing), ntohs(msg->recv_size), ntohs(msg->delay));

	if (conn->state != STATE_ESTB) {
		log_ppp_warn("unexpected PPTP_OUT_CALL_RQST\n");
		if (send_pptp_out_call_rply(conn, msg, 0, PPTP_CALL_RES_GE, PPTP_GE_NOCONN))
			return -1;
		return 0;
	}

	memset(&src_addr, 0, sizeof(src_addr));
	src_addr.sa_family = AF_PPPOX;
	src_addr.sa_protocol = PX_PROTO_PPTP;
	src_addr.sa_addr.pptp.call_id = 0;
	addrlen = sizeof(addr);
	getsockname(conn->hnd.fd, (struct sockaddr*)&addr, &addrlen);
	src_addr.sa_addr.pptp.sin_addr = addr.sin_addr;

	memset(&dst_addr, 0, sizeof(dst_addr));
	dst_addr.sa_family = AF_PPPOX;
	dst_addr.sa_protocol = PX_PROTO_PPTP;
	dst_addr.sa_addr.pptp.call_id = htons(msg->call_id);
	addrlen = sizeof(addr);
	getpeername(conn->hnd.fd, (struct sockaddr*)&addr, &addrlen);
	dst_addr.sa_addr.pptp.sin_addr = addr.sin_addr;

	pptp_sock = socket(AF_PPPOX, SOCK_STREAM, PX_PROTO_PPTP);
	if (pptp_sock < 0) {
		log_ppp_error("failed to create PPTP socket (%s)\n", strerror(errno));
		return -1;
	}

	fcntl(pptp_sock, F_SETFD, fcntl(pptp_sock, F_GETFD) | FD_CLOEXEC);

	if (bind(pptp_sock, (struct sockaddr*)&src_addr, sizeof(src_addr))) {
		log_ppp_error("failed to bind PPTP socket (%s)\n", strerror(errno));
		close(pptp_sock);
		return -1;
	}
	addrlen = sizeof(src_addr);
	getsockname(pptp_sock, (struct sockaddr*)&src_addr, &addrlen);

	if (connect(pptp_sock, (struct sockaddr*)&dst_addr, sizeof(dst_addr))) {
		log_ppp_error("failed to connect PPTP socket (%s)\n", strerror(errno));
		close(pptp_sock);
		return -1;
	}

	if (send_pptp_out_call_rply(conn, msg, src_addr.sa_addr.pptp.call_id, PPTP_CALL_RES_OK, 0))
		return -1;

	conn->call_id = src_addr.sa_addr.pptp.call_id;
	conn->peer_call_id = msg->call_id;
	conn->ppp.fd = pptp_sock;
	conn->ppp.chan_name = _strdup(inet_ntoa(dst_addr.sa_addr.pptp.sin_addr));

	triton_event_fire(EV_CTRL_STARTED, &conn->ppp);

	if (establish_ppp(&conn->ppp)) {
		close(pptp_sock);
		//if (send_pptp_stop_ctrl_conn_rqst(conn, 0, 0))
		conn->state = STATE_FIN;
		return -1;
	}
	conn->state = STATE_PPP;
	__sync_sub_and_fetch(&stat_starting, 1);
	__sync_add_and_fetch(&stat_active, 1);
	
	if (conn->timeout_timer.tpd)
		triton_timer_del(&conn->timeout_timer);

	if (conf_echo_interval) {
		conn->echo_timer.period = conf_echo_interval * 1000;
		triton_timer_add(&conn->ctx, &conn->echo_timer, 0);
	}

	return 0;
}

static int send_pptp_call_disconnect_notify(struct pptp_conn_t *conn, int result)
{
	struct pptp_call_clear_ntfy msg = {
		.header = PPTP_HEADER_CTRL(PPTP_CALL_CLEAR_NTFY),
		.call_id = htons(conn->peer_call_id),
		.result_code = result,
		.error_code = 0,
		.cause_code = 0,
	};

	if (conf_verbose)
		log_ppp_info2("send [PPTP Call-Disconnect-Notify <Call-ID %x> <Result %i> <Error %i> <Cause %i>]\n", ntohs(msg.call_id), msg.result_code, msg.error_code, msg.cause_code);
	
	return post_msg(conn, &msg, sizeof(msg));
}

static int pptp_call_clear_rqst(struct pptp_conn_t *conn)
{
	struct pptp_call_clear_rqst *rqst = (struct pptp_call_clear_rqst *)conn->in_buf;

	if (conf_verbose)
		log_ppp_info2("recv [PPTP Call-Clear-Request <Call-ID %x>]\n", ntohs(rqst->call_id));

	if (conn->echo_timer.tpd)
		triton_timer_del(&conn->echo_timer);

	if (conn->state == STATE_PPP) {
		__sync_sub_and_fetch(&stat_active, 1);
		conn->state = STATE_CLOSE;
		ppp_terminate(&conn->ppp, TERM_USER_REQUEST, 1);
	}

	return send_pptp_call_disconnect_notify(conn, 4);
}

static int pptp_echo_rqst(struct pptp_conn_t *conn)
{
	struct pptp_echo_rqst *in_msg = (struct pptp_echo_rqst *)conn->in_buf;
	struct pptp_echo_rply out_msg = {
		.header = PPTP_HEADER_CTRL(PPTP_ECHO_RPLY),
		.identifier = in_msg->identifier,
		.result_code = 1,
	};

	if (conf_verbose) {
		log_ppp_debug("recv [PPTP Echo-Request <Identifier %x>]\n", in_msg->identifier);
		log_ppp_debug("send [PPTP Echo-Reply <Identifier %x>]\n", out_msg.identifier);
	}

	return post_msg(conn, &out_msg, sizeof(out_msg));
}

static int pptp_echo_rply(struct pptp_conn_t *conn)
{
	struct pptp_echo_rply *msg = (struct pptp_echo_rply *)conn->in_buf;
	
	if (conf_verbose)
		log_ppp_debug("recv [PPTP Echo-Reply <Identifier %x>]\n", msg->identifier);

	/*if (msg->identifier != conn->echo_sent) {
		log_ppp_warn("pptp:echo: identifier mismatch\n");
		//return -1;
	}*/
	conn->echo_sent = 0;
	return 0;
}
static void pptp_send_echo(struct triton_timer_t *t)
{
	struct pptp_conn_t *conn = container_of(t, typeof(*conn), echo_timer);
	struct pptp_echo_rqst msg = {
		.header = PPTP_HEADER_CTRL(PPTP_ECHO_RQST),
	};

	if (++conn->echo_sent == conf_echo_failure) {
		log_ppp_warn("pptp: no echo reply\n");
		disconnect(conn);
		return;
	}

	conn->echo_sent = random();
	msg.identifier = conn->echo_sent;

	if (conf_verbose)
		log_ppp_debug("send [PPTP Echo-Request <Identifier %x>]\n", msg.identifier);

	if (post_msg(conn, &msg, sizeof(msg)))
		disconnect(conn);
}

static int process_packet(struct pptp_conn_t *conn)
{
	struct pptp_header *hdr = (struct pptp_header *)conn->in_buf;
	switch(ntohs(hdr->ctrl_type))
	{
		case PPTP_START_CTRL_CONN_RQST:
			return pptp_start_ctrl_conn_rqst(conn);
		case PPTP_STOP_CTRL_CONN_RQST:
			return pptp_stop_ctrl_conn_rqst(conn);
		case PPTP_STOP_CTRL_CONN_RPLY:
			return pptp_stop_ctrl_conn_rply(conn);
		case PPTP_OUT_CALL_RQST:
			return pptp_out_call_rqst(conn);
		case PPTP_ECHO_RQST:
			return pptp_echo_rqst(conn);
		case PPTP_ECHO_RPLY:
			return pptp_echo_rply(conn);
		case PPTP_CALL_CLEAR_RQST:
			return pptp_call_clear_rqst(conn);
		case PPTP_SET_LINK_INFO:
			if (conf_verbose)
				log_ppp_info2("recv [PPTP Set-Link-Info]\n");
			return 0;
		default:
			log_ppp_warn("recv [PPTP Unknown (%x)]\n", ntohs(hdr->ctrl_type));
	}
	return 0;
}

static int pptp_read(struct triton_md_handler_t *h)
{
	struct pptp_conn_t *conn=container_of(h,typeof(*conn),hnd);
	struct pptp_header *hdr=(struct pptp_header *)conn->in_buf;
	int n;

	while(1) {
		n = read(h->fd, conn->in_buf + conn->in_size, PPTP_CTRL_SIZE_MAX - conn->in_size);
		if (n < 0) {
			if (errno == EINTR)
				continue;
			if (errno == EAGAIN)
				return 0;
			log_ppp_error("pptp: read: %s\n",strerror(errno));
			goto drop;
		}
		if (n == 0) {
			if (conf_verbose)
				log_ppp_info2("pptp: disconnect by peer\n");
			goto drop;
		}
		conn->in_size += n;
		if (conn->in_size >= sizeof(*hdr)) {
			if (hdr->magic != htonl(PPTP_MAGIC)) {
				log_ppp_error("pptp: invalid magic\n");
				goto drop;
			}
			if (ntohs(hdr->length) >= PPTP_CTRL_SIZE_MAX) {
				log_ppp_error("pptp: message is too long\n");
				goto drop;
			}
			if (ntohs(hdr->length) > conn->in_size)
				continue;
			if (ntohs(hdr->length) <= conn->in_size) {
				if (ntohs(hdr->length) != PPTP_CTRL_SIZE(ntohs(hdr->ctrl_type))) {
					log_ppp_error("pptp: invalid message length\n");
					goto drop;
				}
				if (process_packet(conn))
					goto drop;
				conn->in_size -= ntohs(hdr->length);
				if (conn->in_size)
					memmove(conn->in_buf, conn->in_buf + ntohs(hdr->length), conn->in_size);
			}
		}
	}
drop:
	disconnect(conn);
	return 1;
}
static int pptp_write(struct triton_md_handler_t *h)
{
	struct pptp_conn_t *conn = container_of(h, typeof(*conn), hnd);
	int n;

	while (1) {
		n = write(h->fd, conn->out_buf+conn->out_pos, conn->out_size-conn->out_pos);

		if (n < 0) {
			if (errno == EINTR)
				continue;
			if (errno == EAGAIN)
				n = 0;
			else {
				if (errno != EPIPE) {
					if (conf_verbose)
						log_ppp_info2("pptp: post_msg: %s\n", strerror(errno));
				}
				disconnect(conn);
				return 1;
			}
		}

		conn->out_pos += n;
		if (conn->out_pos == conn->out_size) {
			conn->out_pos = 0;
			conn->out_size = 0;
			triton_md_disable_handler(h, MD_MODE_WRITE);
			return 0;
		}
	}
}
static void pptp_timeout(struct triton_timer_t *t)
{
	struct pptp_conn_t *conn = container_of(t, typeof(*conn), timeout_timer);
	disconnect(conn);
}
static void pptp_close(struct triton_context_t *ctx)
{
	struct pptp_conn_t *conn = container_of(ctx, typeof(*conn), ctx);
	if (conn->state == STATE_PPP) {
		__sync_sub_and_fetch(&stat_active, 1);
		conn->state = STATE_CLOSE;
		ppp_terminate(&conn->ppp, TERM_ADMIN_RESET, 1);
		if (send_pptp_call_disconnect_notify(conn, 3)) {
			triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn);
			return;
		}
	} else {
		if (send_pptp_stop_ctrl_conn_rqst(conn, 0)) {
			triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn);
			return;
		}
	}

	if (conn->timeout_timer.tpd)
		triton_timer_mod(&conn->timeout_timer, 0);
	else
		triton_timer_add(ctx, &conn->timeout_timer, 0);
}
static void ppp_started(struct ppp_t *ppp)
{
	log_ppp_debug("pptp: ppp started\n");
}
static void ppp_finished(struct ppp_t *ppp)
{
	struct pptp_conn_t *conn = container_of(ppp, typeof(*conn), ppp);

	if (conn->state != STATE_CLOSE) {
		log_ppp_debug("pptp: ppp finished\n");
		conn->state = STATE_CLOSE;
		__sync_sub_and_fetch(&stat_active, 1);

		if (send_pptp_call_disconnect_notify(conn, 3))
			triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn);
		else if (send_pptp_stop_ctrl_conn_rqst(conn, 0))
			triton_context_call(&conn->ctx, (void (*)(void*))disconnect, conn);
		else {
			if (conn->timeout_timer.tpd)
				triton_timer_mod(&conn->timeout_timer, 0);
			else
				triton_timer_add(&conn->ctx, &conn->timeout_timer, 0);
		}
	}
}

//==================================

struct pptp_serv_t
{
	struct triton_context_t ctx;
	struct triton_md_handler_t hnd;
};

static int pptp_connect(struct triton_md_handler_t *h)
{
  struct sockaddr_in addr;
	socklen_t size = sizeof(addr);
	int sock;
	struct pptp_conn_t *conn;

	while(1) {
		sock = accept(h->fd, (struct sockaddr *)&addr, &size);
		if (sock < 0) {
			if (errno == EAGAIN)
				return 0;
			log_error("pptp: accept failed: %s\n", strerror(errno));
			continue;
		}

		if (ppp_shutdown) {
			close(sock);
			continue;
		}

		if (triton_module_loaded("connlimit") && connlimit_check(cl_key_from_ipv4(addr.sin_addr.s_addr))) {
			close(sock);
			return 0;
		}

		log_info2("pptp: new connection from %s\n", inet_ntoa(addr.sin_addr));

		if (iprange_client_check(addr.sin_addr.s_addr)) {
			log_warn("pptp: IP is out of client-ip-range, droping connection...\n");
			close(sock);
			continue;
		}

		if (fcntl(sock, F_SETFL, O_NONBLOCK)) {
			log_error("pptp: failed to set nonblocking mode: %s, closing connection...\n", strerror(errno));
			close(sock);
			continue;
		}

		conn = mempool_alloc(conn_pool);
		memset(conn, 0, sizeof(*conn));
		conn->hnd.fd = sock;
		conn->hnd.read = pptp_read;
		conn->hnd.write = pptp_write;
		conn->ctx.close = pptp_close;
		conn->ctx.before_switch = log_switch;
		conn->in_buf = _malloc(PPTP_CTRL_SIZE_MAX);
		conn->out_buf = _malloc(PPTP_CTRL_SIZE_MAX);
		conn->timeout_timer.expire = pptp_timeout;
		conn->timeout_timer.period = conf_timeout * 1000;
		conn->echo_timer.expire = pptp_send_echo;
		conn->ctrl.ctx = &conn->ctx;
		conn->ctrl.started = ppp_started;
		conn->ctrl.finished = ppp_finished;
		conn->ctrl.max_mtu = PPTP_MAX_MTU;
		conn->ctrl.type = CTRL_TYPE_PPTP;
		conn->ctrl.name = "pptp";
		
		conn->ctrl.calling_station_id = _malloc(17);
		conn->ctrl.called_station_id = _malloc(17);
		u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.calling_station_id);
		getsockname(sock, &addr, &size);
		u_inet_ntoa(addr.sin_addr.s_addr, conn->ctrl.called_station_id);
	
		ppp_init(&conn->ppp);
		conn->ppp.ctrl = &conn->ctrl;

		triton_context_register(&conn->ctx, &conn->ppp);
		triton_md_register_handler(&conn->ctx, &conn->hnd);
		triton_md_enable_handler(&conn->hnd,MD_MODE_READ);
		triton_timer_add(&conn->ctx, &conn->timeout_timer, 0);
		triton_context_wakeup(&conn->ctx);

		triton_event_fire(EV_CTRL_STARTING, &conn->ppp);

		__sync_add_and_fetch(&stat_starting, 1);
	}
	return 0;
}
static void pptp_serv_close(struct triton_context_t *ctx)
{
	struct pptp_serv_t *s=container_of(ctx,typeof(*s),ctx);
	triton_md_unregister_handler(&s->hnd);
	close(s->hnd.fd);
	triton_context_unregister(ctx);
}

static struct pptp_serv_t serv=
{
	.hnd.read = pptp_connect,
	.ctx.close = pptp_serv_close,
	.ctx.before_switch = log_switch,
};

static int show_stat_exec(const char *cmd, char * const *fields, int fields_cnt, void *client)
{
	cli_send(client, "pptp:\r\n");
	cli_sendv(client,"  starting: %u\r\n", stat_starting);
	cli_sendv(client,"  active: %u\r\n", stat_active);

	return CLI_CMD_OK;
}

void __export pptp_get_stat(unsigned int **starting, unsigned int **active)
{
	*starting = &stat_starting;
	*active = &stat_active;
}

static void load_config(void)
{
	char *opt;

	opt = conf_get_opt("pptp", "timeout");
	if (opt && atoi(opt) > 0)
		conf_timeout = atoi(opt);
	
	opt = conf_get_opt("pptp", "echo-interval");
	if (opt && atoi(opt) >= 0)
		conf_echo_interval = atoi(opt);

	opt = conf_get_opt("pptp", "echo-failure");
	if (opt && atoi(opt) > 0)
		conf_echo_failure = atoi(opt);

	opt = conf_get_opt("pptp", "verbose");
	if (opt && atoi(opt) > 0)
		conf_verbose = 1;
}

static void pptp_init(void)
{
	struct sockaddr_in addr;
	char *opt;

	system("modprobe pptp");

	serv.hnd.fd = socket(PF_INET, SOCK_STREAM, 0);
  if (serv.hnd.fd < 0) {
    log_emerg("pptp: failed to create server socket: %s\n", strerror(errno));
    return;
  }
	
	fcntl(serv.hnd.fd, F_SETFD, fcntl(serv.hnd.fd, F_GETFD) | FD_CLOEXEC);
  
	addr.sin_family = AF_INET;
  addr.sin_port = htons(PPTP_PORT);

	opt = conf_get_opt("pptp", "bind");
	if (opt)
		addr.sin_addr.s_addr = inet_addr(opt);
	else
		addr.sin_addr.s_addr = htonl(INADDR_ANY);
  
  setsockopt(serv.hnd.fd, SOL_SOCKET, SO_REUSEADDR, &serv.hnd.fd, 4);  
  if (bind (serv.hnd.fd, (struct sockaddr *) &addr, sizeof (addr)) < 0) {
    log_emerg("pptp: failed to bind socket: %s\n", strerror(errno));
		close(serv.hnd.fd);
    return;
  }

  if (listen (serv.hnd.fd, 100) < 0) {
    log_emerg("pptp: failed to listen socket: %s\n", strerror(errno));
		close(serv.hnd.fd);
    return;
  }

	if (fcntl(serv.hnd.fd, F_SETFL, O_NONBLOCK)) {
    log_emerg("pptp: failed to set nonblocking mode: %s\n", strerror(errno));
		close(serv.hnd.fd);
    return;
	}
	
	conn_pool = mempool_create(sizeof(struct pptp_conn_t));

	load_config();

	triton_context_register(&serv.ctx, NULL);
	triton_md_register_handler(&serv.ctx, &serv.hnd);
	triton_md_enable_handler(&serv.hnd, MD_MODE_READ);
	triton_context_wakeup(&serv.ctx);

	cli_register_simple_cmd2(show_stat_exec, NULL, 2, "show", "stat");
	
	triton_event_register_handler(EV_CONFIG_RELOAD, (triton_event_func)load_config);
}

DEFINE_INIT(20, pptp_init);
Beispiel #14
0
static int install_tbf(struct rtnl_handle *rth, int ifindex, int rate, int burst)
{
	struct qdisc_opt opt = {
		.kind = "tbf",
		.handle = 0x00010000,
		.parent = TC_H_ROOT,
		.rate = rate,
		.buffer = burst,
		.latency = conf_latency,
		.qdisc = qdisc_tbf,
	};

	return tc_qdisc_modify(rth, ifindex, RTM_NEWQDISC, NLM_F_EXCL|NLM_F_CREATE, &opt);
}

static int install_htb(struct rtnl_handle *rth, int ifindex, int rate, int burst)
{
	struct qdisc_opt opt1 = {
		.kind = "htb",
		.handle = 0x00010000,
		.parent = TC_H_ROOT,
		.quantum = conf_r2q,
		.defcls = 1,
		.qdisc = qdisc_htb_root,
	};

	struct qdisc_opt opt2 = {
		.kind = "htb",
		.handle = 0x00010001,
		.parent = 0x00010000,
		.rate = rate,
		.buffer = burst,
		.quantum = conf_quantum,
		.qdisc = qdisc_htb_class,
	};


	if (tc_qdisc_modify(rth, ifindex, RTM_NEWQDISC, NLM_F_EXCL|NLM_F_CREATE, &opt1))
		return -1;

	if (tc_qdisc_modify(rth, ifindex, RTM_NEWTCLASS, NLM_F_EXCL|NLM_F_CREATE, &opt2))
		return -1;

	return 0;
}

static int install_police(struct rtnl_handle *rth, int ifindex, int rate, int burst)
{
	__u32 rtab[256];
	struct rtattr *tail, *tail1, *tail2, *tail3;
	int Rcell_log = -1;
	int mtu = conf_mtu, flowid = 1;
	unsigned int linklayer  = LINKLAYER_ETHERNET; /* Assume ethernet */

	struct {
			struct nlmsghdr 	n;
			struct tcmsg 		t;
			char buf[TCA_BUF_MAX];
	} req;

	struct qdisc_opt opt1 = {
		.kind = "ingress",
		.handle = 0xffff0000,
		.parent = TC_H_INGRESS,
	};

	struct sel {
		struct tc_u32_sel sel;
		struct tc_u32_key key;
	} sel = {
		.sel.nkeys = 1,
		.sel.flags = TC_U32_TERMINAL,
//		.key.off = 12,
	};

	struct tc_police police = {
		.action = TC_POLICE_SHOT,
		.rate.rate = rate,
		.rate.mpu = conf_mpu,
		.limit = (double)rate * conf_latency + burst,
		.burst = tc_calc_xmittime(rate, burst),
	};

	if (tc_qdisc_modify(rth, ifindex, RTM_NEWQDISC, NLM_F_EXCL|NLM_F_CREATE, &opt1))
		return -1;

	if (tc_calc_rtable(&police.rate, rtab, Rcell_log, mtu, linklayer) < 0) {
		log_ppp_error("shaper: failed to calculate ceil rate table.\n");
		return -1;
	}

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_EXCL|NLM_F_CREATE;
	req.n.nlmsg_type = RTM_NEWTFILTER;
	req.t.tcm_family = AF_UNSPEC;
	req.t.tcm_ifindex = ifindex;
	req.t.tcm_handle = 1;
	req.t.tcm_parent = 0xffff0000;

	req.t.tcm_info = TC_H_MAKE(100 << 16, ntohs(ETH_P_ALL));

	addattr_l(&req.n, sizeof(req), TCA_KIND, "u32", 4);

	tail = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, TCA_OPTIONS, NULL, 0);

	tail1 = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, TCA_U32_ACT, NULL, 0);

	tail2 = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, 1, NULL, 0);
	addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, "police", 7);

	tail3 = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, TCA_ACT_OPTIONS, NULL, 0);
	addattr_l(&req.n, MAX_MSG, TCA_POLICE_TBF, &police, sizeof(police));
	addattr_l(&req.n, MAX_MSG, TCA_POLICE_RATE, rtab, 1024);
	tail3->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail3;

	tail2->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail2;

	tail1->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail1;

	addattr_l(&req.n, MAX_MSG, TCA_U32_CLASSID, &flowid, 4);
	addattr_l(&req.n, MAX_MSG, TCA_U32_SEL, &sel, sizeof(sel));
	tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;

	if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
		return -1;

	return 0;
}

static int install_htb_ifb(struct rtnl_handle *rth, int ifindex, __u32 priority, int rate, int burst)
{
	struct rtattr *tail, *tail1, *tail2, *tail3;

	struct {
			struct nlmsghdr 	n;
			struct tcmsg 		t;
			char buf[TCA_BUF_MAX];
	} req;

	struct qdisc_opt opt1 = {
		.kind = "htb",
		.handle = 0x00010000 + priority,
		.parent = 0x00010000,
		.rate = rate,
		.buffer = burst,
		.quantum = conf_quantum,
		.qdisc = qdisc_htb_class,
	};

	struct qdisc_opt opt2 = {
		.kind = "ingress",
		.handle = 0xffff0000,
		.parent = TC_H_INGRESS,
	};

	struct sel {
		struct tc_u32_sel sel;
		struct tc_u32_key key;
	} sel = {
		.sel.nkeys = 1,
		.sel.flags = TC_U32_TERMINAL,
		.key.off = 0,
	};

	struct tc_skbedit p1 = {
		.action = TC_ACT_PIPE,
	};

	struct tc_mirred p2 = {
		.eaction = TCA_EGRESS_REDIR,
		.action = TC_ACT_STOLEN,
		.ifindex = conf_ifb_ifindex,
	};

	if (tc_qdisc_modify(rth, conf_ifb_ifindex, RTM_NEWTCLASS, NLM_F_EXCL|NLM_F_CREATE, &opt1))
		return -1;

	if (tc_qdisc_modify(rth, ifindex, RTM_NEWQDISC, NLM_F_EXCL|NLM_F_CREATE, &opt2))
		return -1;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_EXCL|NLM_F_CREATE;
	req.n.nlmsg_type = RTM_NEWTFILTER;
	req.t.tcm_family = AF_UNSPEC;
	req.t.tcm_ifindex = ifindex;
	req.t.tcm_handle = 1;
	req.t.tcm_parent = 0xffff0000;

	req.t.tcm_info = TC_H_MAKE(100 << 16, ntohs(ETH_P_ALL));


	addattr_l(&req.n, sizeof(req), TCA_KIND, "u32", 4);

	tail = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, TCA_OPTIONS, NULL, 0);

	tail1 = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, TCA_U32_ACT, NULL, 0);

	// action skbedit priority X pipe
	tail2 = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, 1, NULL, 0);
	addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, "skbedit", 8);

	tail3 = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, TCA_ACT_OPTIONS, NULL, 0);
	addattr_l(&req.n, MAX_MSG, TCA_SKBEDIT_PARMS, &p1, sizeof(p1));
	priority--;
	addattr_l(&req.n, MAX_MSG, TCA_SKBEDIT_PRIORITY, &priority, sizeof(priority));
	tail3->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail3;

	tail2->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail2;

	tail1->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail1;

	// action mirred egress redirect dev ifb0
	tail2 = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, 2, NULL, 0);
	addattr_l(&req.n, MAX_MSG, TCA_ACT_KIND, "mirred", 7);

	tail3 = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, MAX_MSG, TCA_ACT_OPTIONS, NULL, 0);
	addattr_l(&req.n, MAX_MSG, TCA_MIRRED_PARMS, &p2, sizeof(p2));
	tail3->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail3;

	tail2->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail2;

	tail1->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail1;
  //

	addattr32(&req.n, TCA_BUF_MAX, TCA_U32_CLASSID, 1);
	addattr_l(&req.n, MAX_MSG, TCA_U32_SEL, &sel, sizeof(sel));
	tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;

	if (rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0) < 0)
		return -1;

	return 0;
}

static int install_fwmark(struct rtnl_handle *rth, int ifindex, int parent)
{
	struct rtattr *tail;

	struct {
			struct nlmsghdr 	n;
			struct tcmsg 		t;
			char buf[1024];
	} req;

	memset(&req, 0, sizeof(req) - 1024);

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_EXCL|NLM_F_CREATE;
	req.n.nlmsg_type = RTM_NEWTFILTER;
	req.t.tcm_family = AF_UNSPEC;
	req.t.tcm_ifindex = ifindex;
	req.t.tcm_handle = conf_fwmark;
	req.t.tcm_parent = parent;
	req.t.tcm_info = TC_H_MAKE(90 << 16, ntohs(ETH_P_IP));

	addattr_l(&req.n, sizeof(req), TCA_KIND, "fw", 3);
	tail = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, TCA_BUF_MAX, TCA_OPTIONS, NULL, 0);
	addattr32(&req.n, TCA_BUF_MAX, TCA_FW_CLASSID, TC_H_MAKE(1 << 16, 0));
	tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;
	return rtnl_talk(rth, &req.n, 0, 0, NULL, NULL, NULL, 0);
}

static int remove_root(struct rtnl_handle *rth, int ifindex)
{
	struct qdisc_opt opt = {
		.handle = 0x00010000,
		.parent = TC_H_ROOT,
	};

	return tc_qdisc_modify(rth, ifindex, RTM_DELQDISC, 0, &opt);
}

static int remove_ingress(struct rtnl_handle *rth, int ifindex)
{
	struct qdisc_opt opt = {
		.handle = 0xffff0000,
		.parent = TC_H_INGRESS,
	};

	return tc_qdisc_modify(rth, ifindex, RTM_DELQDISC, 0, &opt);
}

static int remove_htb_ifb(struct rtnl_handle *rth, int ifindex, int priority)
{
	struct qdisc_opt opt = {
		.handle = 0x00010000 + priority,
		.parent = 0x00010000,
	};

	return tc_qdisc_modify(rth, conf_ifb_ifindex, RTM_DELTCLASS, 0, &opt);
}

int install_limiter(struct ap_session *ses, int down_speed, int down_burst, int up_speed, int up_burst, int idx)
{
	struct rtnl_handle *rth = net->rtnl_get();
	int r = 0;

	if (!rth) {
		log_ppp_error("shaper: cannot open rtnetlink\n");
		return -1;
	}

	if (down_speed) {
		down_speed = down_speed * 1000 / 8;
		down_burst = down_burst ? down_burst : conf_down_burst_factor * down_speed;

		if (conf_down_limiter == LIM_TBF)
			r = install_tbf(rth, ses->ifindex, down_speed, down_burst);
		else {
			r = install_htb(rth, ses->ifindex, down_speed, down_burst);
			if (r == 0)
				r = install_leaf_qdisc(rth, ses->ifindex, 0x00010001, 0x00020000);
		}
	}

	if (up_speed) {
		up_speed = up_speed * 1000 / 8;
		up_burst = up_burst ? up_burst : conf_up_burst_factor * up_speed;

		if (conf_up_limiter == LIM_POLICE)
			r = install_police(rth, ses->ifindex, up_speed, up_burst);
		else {
			r = install_htb_ifb(rth, ses->ifindex, idx, up_speed, up_burst);
			if (r == 0)
				r = install_leaf_qdisc(rth, conf_ifb_ifindex, 0x00010000 + idx, idx << 16);
		}
	}

	if (conf_fwmark)
		install_fwmark(rth, ses->ifindex, 0x00010000);

	net->rtnl_put(rth);

	return r;
}

int remove_limiter(struct ap_session *ses, int idx)
{
	struct rtnl_handle *rth = net->rtnl_get();

	if (!rth) {
		log_ppp_error("shaper: cannot open rtnetlink\n");
		return -1;
	}

	remove_root(rth, ses->ifindex);
	remove_ingress(rth, ses->ifindex);

	if (conf_up_limiter == LIM_HTB)
		remove_htb_ifb(rth, ses->ifindex, idx);

	net->rtnl_put(rth);

	return 0;
}

int init_ifb(const char *name)
{
	struct rtnl_handle rth;
	struct rtattr *tail;
	struct ifreq ifr;
	int r;
	int sock_fd = socket(AF_INET, SOCK_DGRAM, 0);

	struct {
			struct nlmsghdr 	n;
			struct tcmsg 		t;
			char buf[TCA_BUF_MAX];
	} req;

	struct qdisc_opt opt = {
		.kind = "htb",
		.handle = 0x00010000,
		.parent = TC_H_ROOT,
		.quantum = conf_r2q,
		.qdisc = qdisc_htb_root,
	};

	if (system("modprobe -q ifb"))
		log_warn("failed to load ifb kernel module\n");

	memset(&ifr, 0, sizeof(ifr));
	strcpy(ifr.ifr_name, name);

	if (ioctl(sock_fd, SIOCGIFINDEX, &ifr)) {
		log_emerg("shaper: ioctl(SIOCGIFINDEX): %s\n", strerror(errno));
		close(sock_fd);
		return -1;
	}

	conf_ifb_ifindex = ifr.ifr_ifindex;

	ifr.ifr_flags |= IFF_UP;

	if (ioctl(sock_fd, SIOCSIFFLAGS, &ifr)) {
		log_emerg("shaper: ioctl(SIOCSIFINDEX): %s\n", strerror(errno));
		close(sock_fd);
		return -1;
	}

	if (rtnl_open(&rth, 0)) {
		log_emerg("shaper: cannot open rtnetlink\n");
		close(sock_fd);
		return -1;
	}

	tc_qdisc_modify(&rth, conf_ifb_ifindex, RTM_DELQDISC, 0, &opt);

	r = tc_qdisc_modify(&rth, conf_ifb_ifindex, RTM_NEWQDISC, NLM_F_CREATE | NLM_F_REPLACE, &opt);
	if (r)
		goto out;

	memset(&req, 0, sizeof(req));

	req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct tcmsg));
	req.n.nlmsg_flags = NLM_F_REQUEST|NLM_F_EXCL|NLM_F_CREATE;
	req.n.nlmsg_type = RTM_NEWTFILTER;
	req.t.tcm_family = AF_UNSPEC;
	req.t.tcm_ifindex = conf_ifb_ifindex;
	req.t.tcm_handle = 1;
	req.t.tcm_parent = 0x00010000;
	req.t.tcm_info = TC_H_MAKE(100 << 16, ntohs(ETH_P_ALL));

	addattr_l(&req.n, sizeof(req), TCA_KIND, "flow", 5);

	tail = NLMSG_TAIL(&req.n);
	addattr_l(&req.n, TCA_BUF_MAX, TCA_OPTIONS, NULL, 0);
	addattr32(&req.n, TCA_BUF_MAX, TCA_FLOW_KEYS, 1 << FLOW_KEY_PRIORITY);
	addattr32(&req.n, TCA_BUF_MAX, TCA_FLOW_MODE, FLOW_MODE_MAP);
	tail->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)tail;

	r = rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL, 0);

out:
	rtnl_close(&rth);
	close(sock_fd);

	return r;
}
Beispiel #15
0
static int mru_recv_conf_ack(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr)
{
	struct mru_option_t *mru_opt = container_of(opt,typeof(*mru_opt), opt);
	struct ifreq ifr = {
		.ifr_mtu = mru_opt->mtu,
	};

	strcpy(ifr.ifr_name, lcp->ppp->ses.ifname);

	if (ioctl(lcp->ppp->chan_fd, PPPIOCSMRU, &mru_opt->mru) &&
	    errno != EIO && errno != ENOTTY)
		log_ppp_error("lcp:mru: failed to set channel MRU: %s\n", strerror(errno));

	if (ioctl(lcp->ppp->unit_fd, PPPIOCSMRU, &mru_opt->mru))
		log_ppp_error("lcp:mru: failed to set MRU: %s\n", strerror(errno));

	if (ioctl(sock_fd, SIOCSIFMTU, &ifr))
		log_ppp_error("lcp:mru: failed to set MTU: %s\n", strerror(errno));
	
	return 0;
}

static int mru_recv_conf_nak(struct ppp_lcp_t *lcp, struct lcp_option_t *opt, uint8_t *ptr)
{
	struct mru_option_t *mru_opt = container_of(opt,typeof(*mru_opt), opt);
	mru_opt->naked = 1;
	return 0;
}

static void mru_print(void (*print)(const char *fmt,...), struct lcp_option_t *opt, uint8_t *ptr)
{
	struct mru_option_t *mru_opt = container_of(opt, typeof(*mru_opt), opt);
	struct lcp_opt16_t *opt16 = (struct lcp_opt16_t*)ptr;

	if (ptr)
		print("<mru %i>",ntohs(opt16->val));
	else
		print("<mru %i>",mru_opt->mru);
}

static void load_config(void)
{
	char *opt;

	opt = conf_get_opt("ppp", "mtu");
	if (opt && atoi(opt) > 0)
		conf_mtu = atoi(opt);

	opt = conf_get_opt("ppp", "mru");
	if (opt && atoi(opt) > 0)
		conf_mru = atoi(opt);

	opt = conf_get_opt("ppp", "min-mtu");
	if (opt && atoi(opt) > 0)
		conf_min_mtu = atoi(opt);
	
	opt = conf_get_opt("ppp", "max-mtu");
	if (opt && atoi(opt) > 0)
		conf_max_mtu = atoi(opt);
	
	if (conf_min_mtu > conf_mru) {
		log_emerg("min-mtu cann't be greater then mtu/mru\n");
		conf_min_mtu = conf_mru;
	}

	if (conf_min_mtu > 1500) {
		log_emerg("min-mtu cann't be greater then 1500\n");
		conf_min_mtu = 1500;
	}

	if (conf_mru > 1500 || conf_mtu > 1500) {
		log_emerg("mtu/mru cann't be greater then 1500\n");
		conf_mru = 1500;
	}
}
Beispiel #16
0
int dpado_parse(const char *str)
{
	char *str1 = _strdup(str);
	char *ptr1, *ptr2, *ptr3, *endptr;
	LIST_HEAD(range_list);
	struct dpado_range_t *r;

	strip(str1);

	ptr1 = str1;

	while (1) {
		ptr2 = strchr(ptr1, ',');
		if (ptr2)
			*ptr2 = 0;
		ptr3 = strchr(ptr1, ':');
		if (ptr3)
			*ptr3 = 0;

		r = _malloc(sizeof(*r));
		memset(r, 0, sizeof(*r));

		r->pado_delay = strtol(ptr1, &endptr, 10);
		if (*endptr)
			goto out_err;

		if (list_empty(&range_list))
			r->conn_cnt = INT_MAX;
		else {
			if (!ptr3)
				goto out_err;
			r->conn_cnt = strtol(ptr3 + 1, &endptr, 10);
			if (*endptr)
				goto out_err;
		}

		list_add_tail(&r->entry, &range_list);
		//printf("parsed range: %i:%i\n", r->pado_delay, r->conn_cnt);

		if (!ptr2)
			break;

		ptr1 = ptr2 + 1;
	}

	pthread_mutex_lock(&dpado_range_lock);
	while (!list_empty(&dpado_range_list)) {
		r = list_entry(dpado_range_list.next, typeof(*r), entry);
		list_del(&r->entry);
		_free(r);
	}

	dpado_range_next = NULL;
	dpado_range_prev = NULL;

	while (!list_empty(&range_list)) {
		r = list_entry(range_list.next, typeof(*r), entry);
		list_del(&r->entry);
		list_add_tail(&r->entry, &dpado_range_list);

		if (!dpado_range_prev || stat_active >= r->conn_cnt)
			dpado_range_prev = r;
		else if (!dpado_range_next)
			dpado_range_next = r;
	}

	pado_delay = dpado_range_prev->pado_delay;

	if (conf_pado_delay)
		_free(conf_pado_delay);
	conf_pado_delay = _strdup(str);
	/*printf("active=%i, prev=%i:%i, next=%i:%i, pado_delay=%i\n", stat_active,
	dpado_range_prev?dpado_range_prev->pado_delay:0,dpado_range_prev?dpado_range_prev->conn_cnt:0,
	dpado_range_next?dpado_range_next->pado_delay:0,dpado_range_next?dpado_range_next->conn_cnt:0,
	pado_delay);*/

	pthread_mutex_unlock(&dpado_range_lock);

	_free(str1);
	return 0;

out_err:
	_free(str1);
	log_emerg("pppoe: pado_delay: invalid format\n");
	return -1;
}