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); }
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); }
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); }
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; } }
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; }
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; }
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)); }
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; }
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);
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; }
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);
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; }
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; } }
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; }