int handle_pool4_config(struct xlator *jool, struct genl_info *info) { struct request_hdr *hdr = get_jool_hdr(info); union request_pool4 *request = (union request_pool4 *)(hdr + 1); int error; if (xlat_is_siit()) { log_err("SIIT doesn't have pool4."); return nlcore_respond(info, -EINVAL); } error = validate_request_size(info, sizeof(*request)); if (error) return nlcore_respond(info, error); switch (hdr->operation) { case OP_FOREACH: return handle_pool4_display(jool->nat64.pool4, info, request); case OP_ADD: return handle_pool4_add(jool->nat64.pool4, info, request); case OP_UPDATE: return handle_pool4_update(jool->nat64.pool4, info, request); case OP_REMOVE: return handle_pool4_rm(jool, info, request); case OP_FLUSH: return handle_pool4_flush(jool, info, request); } log_err("Unknown operation: %u", hdr->operation); return nlcore_respond(info, -EINVAL); }
static verdict handle_icmp6(struct xlation *state, struct pkt_metadata const *meta) { union { struct icmp6hdr icmp; struct frag_hdr frag; } buffer; union { struct icmp6hdr *icmp; struct frag_hdr *frag; } ptr; verdict result; ptr.icmp = skb_hdr_ptr(state->in.skb, meta->l4_offset, buffer.icmp); if (!ptr.icmp) return truncated(state, "ICMPv6 header"); if (has_inner_pkt6(ptr.icmp->icmp6_type)) { result = validate_inner6(state, meta); if (result != VERDICT_CONTINUE) return result; } if (xlat_is_siit() && meta->has_frag_hdr && is_icmp6_info(ptr.icmp->icmp6_type)) { ptr.frag = skb_hdr_ptr(state->in.skb, meta->frag_offset, buffer.frag); if (!ptr.frag) return truncated(state, "fragment header"); if (is_fragmented_ipv6(ptr.frag)) { log_debug("Packet is a fragmented ping; its checksum cannot be translated."); return drop(state, JSTAT_FRAGMENTED_PING); } } return VERDICT_CONTINUE; }
int handle_session_config(struct xlator *jool, struct genl_info *info) { struct request_hdr *hdr; struct request_session *request; int error; if (xlat_is_siit()) { log_err("SIIT doesn't have session tables."); return nlcore_respond(info, -EINVAL); } hdr = get_jool_hdr(info); request = (struct request_session *)(hdr + 1); error = validate_request_size(info, sizeof(*request)); if (error) return nlcore_respond(info, error); switch (be16_to_cpu(hdr->operation)) { case OP_DISPLAY: return handle_session_display(jool->nat64.bib, info, request); case OP_COUNT: return handle_session_count(jool->nat64.bib, info, request); } log_err("Unknown operation: %u", be16_to_cpu(hdr->operation)); return nlcore_respond(info, -EINVAL); }
static int handle_session_config(struct nlmsghdr *nl_hdr, struct request_hdr *jool_hdr, struct request_session *request) { __u64 count; int error; if (xlat_is_siit()) { log_err("SIIT doesn't have session tables."); return -EINVAL; } switch (jool_hdr->operation) { case OP_DISPLAY: return handle_session_display(nl_hdr, request); case OP_COUNT: log_debug("Returning session count."); error = sessiondb_count(request->l4_proto, &count); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &count, sizeof(count)); default: log_err("Unknown operation: %d", jool_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
static int handle_pool4_config(struct nlmsghdr *nl_hdr, struct request_hdr *jool_hdr, union request_pool4 *request) { struct response_pool4_count counters; if (xlat_is_siit()) { log_err("SIIT doesn't have pool4."); return -EINVAL; } switch (jool_hdr->operation) { case OP_DISPLAY: return handle_pool4_display(nl_hdr, request); case OP_COUNT: log_debug("Returning IPv4 pool counters."); pool4db_count(&counters.tables, &counters.samples, &counters.taddrs); return respond_setcfg(nl_hdr, &counters, sizeof(counters)); case OP_ADD: return handle_pool4_add(nl_hdr, request); case OP_REMOVE: return handle_pool4_rm(nl_hdr, request); case OP_FLUSH: return handle_pool4_flush(nl_hdr, request); default: log_err("Unknown operation: %d", jool_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
static int validate_version(struct request_hdr *hdr) { if (hdr->magic[0] != 'j' || hdr->magic[1] != 'o') goto magic_fail; if (hdr->magic[2] != 'o' || hdr->magic[3] != 'l') goto magic_fail; switch (hdr->type) { case 's': if (xlat_is_nat64()) { log_err("You're speaking to NAT64 Jool using " "the SIIT Jool application."); return -EINVAL; } break; case 'n': if (xlat_is_siit()) { log_err("You're speaking to SIIT Jool using " "the NAT64 Jool application."); return -EINVAL; } break; default: goto magic_fail; } if (xlat_version() == hdr->version) return 0; log_err("Version mismatch. The kernel module is %u.%u.%u.%u, " "but the userspace application is %u.%u.%u.%u. " "Please update Jool's %s.", JOOL_VERSION_MAJOR, JOOL_VERSION_MINOR, JOOL_VERSION_REV, JOOL_VERSION_DEV, hdr->version >> 24, (hdr->version >> 16) & 0xFFU, (hdr->version >> 8) & 0xFFU, hdr->version & 0xFFU, (xlat_version() > hdr->version) ? "userspace application" : "kernel module"); return -EINVAL; magic_fail: log_err("It appears you're trying to speak to Jool using some other " "Netlink client or an older userspace application. " "If the latter is true, please update your userspace " "application."); return -EINVAL; }
static int do_parsing(char *buffer) { int error; cJSON *json = cJSON_Parse(buffer); if (!json) { log_err("The JSON parser got confused around about here:"); log_err("%s", cJSON_GetErrorPtr()); return -EINVAL; } error = validate_file_type(json); if (error) return error; return xlat_is_siit() ? parse_siit_json(json) : parse_nat64_json(json); }
static int validate_file_type(cJSON *json_structure) { char *siit = "SIIT"; char *nat64 = "NAT64"; char *expected; cJSON *file_type = cJSON_GetObjectItem(json_structure, "File_Type"); if (!file_type) return 0; /* The user doesn't care. */ expected = xlat_is_siit() ? siit : nat64; if (strcasecmp(file_type->valuestring, expected) != 0) { log_err("File_Type is supposed to be '%s' (got '%s').", expected, file_type->valuestring); return -EINVAL; } return 0; }
static int handle_bib_config(struct nlmsghdr *nl_hdr, struct request_hdr *jool_hdr, struct request_bib *request) { __u64 count; int error; if (xlat_is_siit()) { log_err("SIIT doesn't have BIBs."); return -EINVAL; } switch (jool_hdr->operation) { case OP_DISPLAY: return handle_bib_display(nl_hdr, request); case OP_COUNT: log_debug("Returning BIB count."); error = bibdb_count(request->l4_proto, &count); if (error) return respond_error(nl_hdr, error); return respond_setcfg(nl_hdr, &count, sizeof(count)); case OP_ADD: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Adding BIB entry."); return respond_error(nl_hdr, add_static_route(request)); case OP_REMOVE: if (verify_superpriv()) return respond_error(nl_hdr, -EPERM); log_debug("Removing BIB entry."); return respond_error(nl_hdr, delete_static_route(request)); default: log_err("Unknown operation: %d", jool_hdr->operation); return respond_error(nl_hdr, -EINVAL); } }
static verdict handle_icmp4(struct xlation *state, struct pkt_metadata *meta) { struct icmphdr buffer, *ptr; verdict result; ptr = skb_hdr_ptr(state->in.skb, meta->l4_offset, buffer); if (!ptr) return truncated(state, "ICMP header"); if (has_inner_pkt4(ptr->type)) { result = validate_inner4(state, meta); if (result != VERDICT_CONTINUE) return result; } if (xlat_is_siit() && is_icmp4_info(ptr->type) && is_fragmented_ipv4(ip_hdr(state->in.skb))) { log_debug("Packet is a fragmented ping; its checksum cannot be translated."); return drop(state, JSTAT_FRAGMENTED_PING); } return VERDICT_CONTINUE; }