static int rdllib_init (struct rdllib *rl) { char *error = NULL; /* dlopen liblua.so to pickup symbols that will be referenced by * "require" */ dlopen ("liblua.so", RTLD_NOW | RTLD_GLOBAL); if ((error = dlerror()) != NULL) dlopen ("liblua5.1.so", RTLD_NOW | RTLD_GLOBAL); if ((error = dlerror()) != NULL) { VERR (rl, "dlopen(liblua.so) failed: %s\n", error); return (-1); } /* XXX: Is there no equivalent from C? */ lua_getglobal (rl->L, "require"); lua_pushstring (rl->L, "RDL"); if (lua_pcall (rl->L, 1, 1, 0)) { VERR (rl, "loading RDL: %s\n", lua_tostring (rl->L, -1)); return (-1); } if (!lua_istable (rl->L, -1)) { VERR (rl, "Failed to load RDL: %s\n", lua_tostring (rl->L, -1)); } /* * Assign implementation to global RDL table. */ lua_setglobal (rl->L, "RDL"); lua_settop (rl->L, 0); return (0); }
static int dns_init_sockets() { struct addrinfo hints; struct addrinfo *addr_ip; int r; local_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (0 != setnonblock(local_sock)) return -1; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; if (0 != (r = getaddrinfo(listen_addr, listen_port, &hints, &addr_ip))) { VERR("%s:%s:%s\n", gai_strerror(r), listen_addr, listen_port); return -1; } if (0 != bind(local_sock, addr_ip->ai_addr, addr_ip->ai_addrlen)) { ERR("bind"); VERR("Can't bind address %s:%s\n", listen_addr, listen_port); return -1; } freeaddrinfo(addr_ip); remote_sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (0 != setnonblock(remote_sock)) return -1; return 0; }
static int parse_chnroute() { FILE *fp; char line_buf[32]; char *line; size_t len = sizeof(line_buf); ssize_t read; char net[32]; chnroute_list.entries = 0; int i = 0; if (chnroute_file == NULL) { VERR("CHNROUTE_FILE not specified, CHNRoute is disabled\n"); return 0; } fp = fopen(chnroute_file, "rb"); if (fp == NULL) { ERR("fopen"); VERR("Can't open chnroute: %s\n", chnroute_file); return -1; } while ((line = fgets(line_buf, len, fp))) { chnroute_list.entries++; } chnroute_list.nets = calloc(chnroute_list.entries, sizeof(net_mask_t)); if (0 != fseek(fp, 0, SEEK_SET)) { VERR("fseek"); return -1; } while ((line = fgets(line_buf, len, fp))) { char *sp_pos; sp_pos = strchr(line, '\r'); if (sp_pos) *sp_pos = 0; sp_pos = strchr(line, '\n'); if (sp_pos) *sp_pos = 0; sp_pos = strchr(line, '/'); if (sp_pos) { *sp_pos = 0; chnroute_list.nets[i].mask = (1 << (32 - atoi(sp_pos + 1))) - 1; } else { chnroute_list.nets[i].mask = UINT32_MAX; } if (0 == inet_aton(line, &chnroute_list.nets[i].net)) { VERR("invalid addr %s in %s:%d\n", line, chnroute_file, i + 1); return 1; } i++; } qsort(chnroute_list.nets, chnroute_list.entries, sizeof(net_mask_t), cmp_net_mask); fclose(fp); return 0; }
static int parse_chnroute() { FILE * fp; char * line = NULL; size_t len = 0; ssize_t read; char net[32]; chnroute_list.entries = 0; int i = 0; if (chnroute_file == NULL) { VERR("CHNROUTE_FILE not specified, CHNRoute is disabled\n"); return 0; } fp = fopen(chnroute_file, "rb"); if (fp == NULL) { ERR("fopen"); VERR("Can't open chnroute: %s\n", chnroute_file); return -1; } while ((read = getline(&line, &len, fp)) != -1) { chnroute_list.entries++; } if (line) free(line); line = NULL; chnroute_list.nets = calloc(chnroute_list.entries, sizeof(net_mask_t)); if (0 != fseek(fp, 0, SEEK_SET)) { VERR("fseek"); return -1; } while ((read = getline(&line, &len, fp)) != -1) { char *sp_pos = strchr(line, '/'); *sp_pos = 0; chnroute_list.nets[i].mask = (1 << (32 - atoi(sp_pos + 1))) - 1; inet_aton(line, &chnroute_list.nets[i].net); i++; } if (line) free(line); qsort(chnroute_list.nets, chnroute_list.entries, sizeof(net_mask_t), cmp_net_mask); fclose(fp); return 0; }
void rdl_resource_delete_tag (struct resource *r, const char *tag) { if (rdl_resource_method_call1_string (r, "delete_tag", tag) < 0) { VERR (r->rdl->rl, "delete_tag (%s): %s\n", tag, lua_tostring (r->rdl->L, -1)); } }
static int rdl_dostringf (struct rdl *rdl, const char *fmt, ...) { char *s; int rc; int top; va_list ap; va_start (ap, fmt); rc = vasprintf (&s, fmt, ap); va_end (ap); if (rc < 0) return (-1); top = lua_gettop (rdl->L); if ( luaL_loadstring (rdl->L, s) || lua_pcall (rdl->L, 0, LUA_MULTRET, 0)) { VERR (rdl->rl, "dostring (%s): %s\n", s, lua_tostring (rdl->L, -1)); lua_settop (rdl->L, 0); free (s); return (-1); } free (s); return (lua_gettop (rdl->L) - top); }
bool rdl_accumulator_is_empty (struct rdl_accumulator *a) { bool ret_val = true; lua_State *L = a->rdl->L; lua_rdl_accumulator_method_push (a, "is_empty"); if (lua_pcall (L, 1, LUA_MULTRET, 0)) { VERR (a->rdl->rl, "accumulator_is_empty had an error in pcall. Additional info: %s\n", lua_tostring (L, -1)); } else if (lua_isnoneornil (L, -1)) { VERR (a->rdl->rl, "lua method 'is_empty' returned none or nil. Additional info: %s\n", lua_tostring (L, -1)); } else { ret_val = lua_toboolean(L, -1); } lua_settop (L, 0); return ret_val; }
int rdl_accumulator_add (struct rdl_accumulator *a, struct resource *r) { size_t n = rdl_resource_available (r); if (n <= 0) { VERR (a->rdl->rl, "accumulator_add: Insufficient capacity in resource"); return (-1); } return rdl_accumulator_add_n (a, r, n); }
struct rdl * rdl_find (struct rdl *rdl, json_object *args) { lua_rdl_method_push (rdl, "find"); if (json_object_to_lua (rdl->L, args) < 0) { VERR (rdl->rl, "Failed to convert JSON to Lua\n"); return (NULL); } /* * stack: [ Method, object, args-table ] */ if (lua_pcall (rdl->L, 2, LUA_MULTRET, 0) || lua_isnoneornil (rdl->L, 1)) { VERR (rdl->rl, "find(%s): %s\n", json_object_to_json_string (args), lua_tostring (rdl->L, -1)); return (NULL); } return (lua_pop_new_rdl (rdl)); }
static int parse_ip_list() { FILE *fp; char line_buf[32]; char *line = NULL; size_t len = sizeof(line_buf); ssize_t read; ip_list.entries = 0; int i = 0; if (ip_list_file == NULL) return 0; fp = fopen(ip_list_file, "rb"); if (fp == NULL) { ERR("fopen"); VERR("Can't open ip list: %s\n", ip_list_file); return -1; } while ((line = fgets(line_buf, len, fp))) { ip_list.entries++; } ip_list.ips = calloc(ip_list.entries, sizeof(struct in_addr)); if (0 != fseek(fp, 0, SEEK_SET)) { VERR("fseek"); return -1; } while ((line = fgets(line_buf, len, fp))) { char *sp_pos; sp_pos = strchr(line, '\r'); if (sp_pos) *sp_pos = 0; sp_pos = strchr(line, '\n'); if (sp_pos) *sp_pos = 0; inet_aton(line, &ip_list.ips[i]); i++; } qsort(ip_list.ips, ip_list.entries, sizeof(struct in_addr), cmp_in_addr); fclose(fp); return 0; }
char * rdl_accumulator_serialize (struct rdl_accumulator *a) { char *s; lua_State *L = a->rdl->L; lua_rdl_accumulator_method_push (a, "serialize"); if (lua_pcall (L, 1, LUA_MULTRET, 0)) { VERR (a->rdl->rl, "accumulator:serialize: %s\n", lua_tostring (L, -1)); return (NULL); } asprintf (&s, "-- RDL v1.0\n%s", lua_tostring (L, -1)); lua_settop (L, 0); return (s); }
/* * Call [method] on resource [r] and return resulting Lua table * as a json-c json_object. */ static json_object * rdl_resource_method_to_json (struct resource *r, const char *method) { json_object *o = NULL; lua_State *L = r->rdl->L; if (lua_rdl_resource_method_call (r, method)) { VERR (r->rdl->rl, "json: %s\n", lua_tostring (L, -1)); return (NULL); } if (lua_type (L, -1) != LUA_TTABLE) { VERR (r->rdl->rl, "json: Failed to get table. Got %s\n", luaL_typename (L, -1)); lua_pop (L, 1); return (NULL); } if (lua_value_to_json (L, -1, &o) < 0) o = NULL; /* Keep Lua stack clean */ lua_settop (L, 0); return (o); }
struct resource * rdl_resource_get (struct rdl *rdl, const char *uri) { struct resource *r; if (uri == NULL) uri = "default"; rdl_dostringf (rdl, "return rdl:resource ('%s')", uri); if (lua_type (rdl->L, -1) != LUA_TTABLE) { VERR (rdl->rl, "resource (%s): %s\n", uri, lua_tostring (rdl->L, -1)); return (NULL); } r = create_resource_ref (rdl, -1); lua_settop (rdl->L, 0); return (r); }
static int parse_ip_list() { FILE * fp; char * line = NULL; size_t len = 0; ssize_t read; ip_list.entries = 0; int i = 0; fp = fopen(ip_list_file, "rb"); if (fp == NULL) { ERR("fopen"); VERR("Can't open ip list: %s\n", ip_list_file); return -1; } while ((read = getline(&line, &len, fp)) != -1) { ip_list.entries++; } if (line) free(line); line = NULL; ip_list.ips = calloc(ip_list.entries, sizeof(struct in_addr)); if (0 != fseek(fp, 0, SEEK_SET)) { VERR("fseek"); return -1; } while ((read = getline(&line, &len, fp)) != -1) { inet_aton(line, &ip_list.ips[i]); i++; } if (line) free(line); qsort(ip_list.ips, ip_list.entries, sizeof(struct in_addr), cmp_in_addr); fclose(fp); return 0; }
static struct rdl * loadfn (struct rdllib *rl, const char *fn, const char *s) { int rc; struct rdl * rdl = rdl_new (rl); if (rdl == NULL) return NULL; /* * First, get function to evaluate rdl: */ rc = rdl_dostringf (rdl, "return require 'RDL'.%s", fn); if (rc <= 0) { VERR (rl, "rdl_load: Failed to get function RDL.%s\n", fn); rdl_destroy (rdl); return (NULL); } /* * Now push function arg `s' onto stack, and evaluate the function: */ if (s) lua_pushstring (rdl->L, s); if (lua_pcall (rdl->L, s?1:0, LUA_MULTRET, 0)) { VERR (rl, "rdl_load: RDL.%s: %s\n", fn, lua_tostring (rdl->L, -1)); rdl_destroy (rdl); return (NULL); } if (lua_type (rdl->L, -1) != LUA_TTABLE) { VERR (rl, "rdl_load: %s\n", lua_tostring (rdl->L, -1)); rdl_destroy (rdl); return (NULL); } lua_setglobal (rdl->L, "rdl"); lua_settop (rdl->L, 0); return (rdl); }
struct rdl_accumulator * rdl_accumulator_create (struct rdl *rdl) { struct rdl_accumulator *a; rdl_dostringf (rdl, "return rdl:resource_accumulator()"); if (lua_type (rdl->L, -1) != LUA_TTABLE) { VERR (rdl->rl, "accumlator_create: %s\n", lua_tostring (rdl->L, -1)); return (NULL); } a = malloc (sizeof (*a)); a->lua_ref = luaL_ref (rdl->L, LUA_GLOBALSINDEX); a->rdl = rdl; lua_settop (rdl->L, 0); return (a); }
struct resource * rdl_resource_next_child (struct resource *r) { struct resource *c; if (lua_rdl_resource_method_call (r, "next_child")) { VERR (r->rdl->rl, "next child: %s\n", lua_tostring (r->rdl->L, -1)); return NULL; } if (lua_isnil (r->rdl->L, -1)) { /* End of child list is indicated by nil return */ return (NULL); } c = create_resource_ref (r->rdl, -1); lua_settop (r->rdl->L, 0); return (c); }
int rdl_resource_set_int (struct resource *r, const char *tag, int64_t val) { int rc = 0; lua_State *L = r->rdl->L; if (lua_rdl_resource_method_push (r, "tag") < 0) return (-1); lua_pushstring (L, tag); lua_pushnumber (L, val); if (lua_pcall (L, 3, LUA_MULTRET, 0) || lua_isnoneornil (L, 1)) { VERR (r->rdl->rl, "%s(%s): %s\n", "tag", tag, lua_tostring (L, -1)); rc = -1; } lua_settop (L, 0); return (rc); }
struct rdl * rdl_accumulator_copy (struct rdl_accumulator *a) { struct rdl *rdl; char *s; if (a == NULL) return (NULL); if ((s = rdl_accumulator_serialize (a)) == NULL) { VERR (a->rdl->rl, "serialization failure\n"); return (NULL); } rdl = rdl_load (a->rdl->rl, s); free (s); return (rdl); }
const char *rdl_next_hierarchy (struct rdl *rdl, const char *last) { lua_rdl_method_push (rdl, "hierarchy_next"); if (last) lua_pushstring (rdl->L, last); else lua_pushnil (rdl->L); /* stack: [ Method, object, last ] */ if (lua_pcall (rdl->L, 2, LUA_MULTRET, 0)) { VERR (rdl->rl, "next_hierarchy: %s\n", lua_tostring (rdl->L, -1)); return (NULL); } if (lua_isnil (rdl->L, -1)) { /* End of child list is indicated by nil return */ return (NULL); } return (lua_tostring (rdl->L, -1)); }
int rdl_accumulator_add_n (struct rdl_accumulator *a, struct resource *r, size_t n) { int rc = 0; lua_State *L = a->rdl->L; lua_rdl_accumulator_method_push (a, "add"); if (lua_rdl_resource_getfield (r, "uuid") < 0) return (-1); lua_pushnumber (L, n); /* Stack: [ Method, Object, arg1, arg2 ] */ if (lua_pcall (L, 3, LUA_MULTRET, 0) || lua_isnoneornil (L, 1)) { VERR (a->rdl->rl, "accumulator_add: %s\n", lua_tostring (L, -1)); rc = -1; } lua_settop (L, 0); return rc; }
static int resolve_dns_servers() { struct addrinfo hints; struct addrinfo *addr_ip; char* token; int r; int i = 0; char *pch = strchr(dns_servers, ','); dns_servers_len = 1; while (pch != NULL) { dns_servers_len++; pch = strchr(pch + 1, ','); } dns_server_addrs = calloc(dns_servers_len, sizeof(id_addr_t)); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ token = strtok(dns_servers, ","); while (token) { char *port; memset(global_buf, 0, BUF_SIZE); strncpy(global_buf, token, BUF_SIZE - 1); port = (strrchr(global_buf, ':')); if (port) { *port = '\0'; port++; } else { port = "53"; } if (0 != (r = getaddrinfo(global_buf, port, &hints, &addr_ip))) { VERR("%s:%s\n", gai_strerror(r), token); return -1; } dns_server_addrs[i].addr = addr_ip->ai_addr; dns_server_addrs[i].addrlen = addr_ip->ai_addrlen; i++; token = strtok(0, ","); } return 0; }
static int rdl_resource_method_call1_keepstack (struct resource *r, const char *method, enum method_arg_type mtype, void *argptr) { int rc = 0; lua_State *L = r->rdl->L; if (lua_rdl_resource_method_push (r, method) < 0) return (-1); if (mtype == M_ARG_TYPE_STRING) lua_pushstring (L, *(char **)argptr); else if (mtype == M_ARG_TYPE_INTEGER) lua_pushinteger (L, (lua_Integer) *(size_t *)argptr); /* * stack: [ Method, object, arg ] */ if (lua_pcall (L, 2, LUA_MULTRET, 0) || lua_isnoneornil (L, 1)) { VERR (r->rdl->rl, "%s(): %s\n", method, lua_tostring (L, -1)); lua_settop (L, 0); rc = -1; } return (rc); }
int main(int argc, char **argv) { fd_set readset, errorset; int max_fd; memset(&id_addr_queue, 0, sizeof(id_addr_queue)); memset(&delay_queue, 0, sizeof(delay_queue)); if (0 != parse_args(argc, argv)) return EXIT_FAILURE; if (0 != parse_ip_list()) return EXIT_FAILURE; if (0 != parse_chnroute()) return EXIT_FAILURE; if (0 != resolve_dns_servers()) return EXIT_FAILURE; if (0 != dns_init_sockets()) return EXIT_FAILURE; printf("%s\n", version); max_fd = MAX(local_sock, remote_sock) + 1; while (1) { FD_ZERO(&readset); FD_ZERO(&errorset); FD_SET(local_sock, &readset); FD_SET(local_sock, &errorset); FD_SET(remote_sock, &readset); FD_SET(remote_sock, &errorset); struct timeval timeout = { .tv_sec = 1, .tv_usec = 0, }; if (-1 == select(max_fd, &readset, NULL, &errorset, &timeout)) { ERR("select"); return EXIT_FAILURE; } check_and_send_delay(); if (FD_ISSET(local_sock, &errorset)) { // TODO getsockopt(..., SO_ERROR, ...); VERR("local_sock error\n"); return EXIT_FAILURE; } if (FD_ISSET(remote_sock, &errorset)) { // TODO getsockopt(..., SO_ERROR, ...); VERR("remote_sock error\n"); return EXIT_FAILURE; } if (FD_ISSET(local_sock, &readset)) dns_handle_local(); if (FD_ISSET(remote_sock, &readset)) dns_handle_remote(); } return EXIT_SUCCESS; } static int setnonblock(int sock) { int flags; flags = fcntl(sock, F_GETFL, 0); if (flags == -1) { ERR("fcntl"); return -1; } if (-1 == fcntl(sock, F_SETFL, flags | O_NONBLOCK)) { ERR("fcntl"); return -1; } return 0; }
void rdl_resource_iterator_reset (struct resource *r) { if (lua_rdl_resource_method_call (r, "reset")) VERR (r->rdl->rl, "iterator reset: %s\n", lua_tostring (r->rdl->L, -1)); }
static int resolve_dns_servers() { struct addrinfo hints; struct addrinfo *addr_ip; char* token; int r; int i = 0; char *pch = strchr(dns_servers, ','); has_chn_dns = 0; int has_foreign_dns = 0; dns_servers_len = 1; if (compression) { if (!chnroute_file) { VERR("Chnroutes are necessary when using DNS compression pointer mutation\n"); return -1; } } while (pch != NULL) { dns_servers_len++; pch = strchr(pch + 1, ','); } dns_server_addrs = calloc(dns_servers_len, sizeof(id_addr_t)); memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ token = strtok(dns_servers, ","); while (token) { char *port; memset(global_buf, 0, BUF_SIZE); strncpy(global_buf, token, BUF_SIZE - 1); port = (strrchr(global_buf, ':')); if (port) { *port = '\0'; port++; } else { port = "53"; } if (0 != (r = getaddrinfo(global_buf, port, &hints, &addr_ip))) { VERR("%s:%s\n", gai_strerror(r), token); return -1; } if (compression) { if (test_ip_in_list(((struct sockaddr_in *)addr_ip->ai_addr)->sin_addr, &chnroute_list)) { dns_server_addrs[has_chn_dns].addr = addr_ip->ai_addr; dns_server_addrs[has_chn_dns].addrlen = addr_ip->ai_addrlen; has_chn_dns++; } else { has_foreign_dns++; dns_server_addrs[dns_servers_len - has_foreign_dns].addr = addr_ip->ai_addr; dns_server_addrs[dns_servers_len - has_foreign_dns].addrlen = addr_ip->ai_addrlen; } token = strtok(0, ","); } else { dns_server_addrs[i].addr = addr_ip->ai_addr; dns_server_addrs[i].addrlen = addr_ip->ai_addrlen; i++; token = strtok(0, ","); if (chnroute_file) { if (test_ip_in_list(((struct sockaddr_in *)addr_ip->ai_addr)->sin_addr, &chnroute_list)) { has_chn_dns = 1; } else { has_foreign_dns = 1; } } } } if (chnroute_file) { if (!(has_chn_dns && has_foreign_dns)) { if (compression) { VERR("You should have at least one Chinese DNS and one foreign DNS when " "using DNS compression pointer mutation\n"); return -1; } else { VERR("You should have at least one Chinese DNS and one foreign DNS when " "chnroutes is enabled\n"); return 0; } } } return 0; }