| /* |
| * (C) 2005-2011 by Pablo Neira Ayuso <pablo@netfilter.org> |
| * |
| * This program is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| */ |
| |
| #include "internal/internal.h" |
| #include <linux/icmp.h> |
| #include <linux/icmpv6.h> |
| |
| static const uint8_t invmap_icmp[] = { |
| [ICMP_ECHO] = ICMP_ECHOREPLY + 1, |
| [ICMP_ECHOREPLY] = ICMP_ECHO + 1, |
| [ICMP_TIMESTAMP] = ICMP_TIMESTAMPREPLY + 1, |
| [ICMP_TIMESTAMPREPLY] = ICMP_TIMESTAMP + 1, |
| [ICMP_INFO_REQUEST] = ICMP_INFO_REPLY + 1, |
| [ICMP_INFO_REPLY] = ICMP_INFO_REQUEST + 1, |
| [ICMP_ADDRESS] = ICMP_ADDRESSREPLY + 1, |
| [ICMP_ADDRESSREPLY] = ICMP_ADDRESS + 1 |
| }; |
| |
| #ifndef ICMPV6_NI_QUERY |
| #define ICMPV6_NI_QUERY 139 |
| #endif |
| |
| #ifndef ICMPV6_NI_REPLY |
| #define ICMPV6_NI_REPLY 140 |
| #endif |
| |
| static const uint8_t invmap_icmpv6[] = { |
| [ICMPV6_ECHO_REQUEST - 128] = ICMPV6_ECHO_REPLY + 1, |
| [ICMPV6_ECHO_REPLY - 128] = ICMPV6_ECHO_REQUEST + 1, |
| [ICMPV6_NI_QUERY - 128] = ICMPV6_NI_QUERY + 1, |
| [ICMPV6_NI_REPLY - 128] = ICMPV6_NI_REPLY + 1 |
| }; |
| |
| static void |
| set_attr_orig_ipv4_src(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->head.orig.src.v4 = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_orig_ipv4_dst(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->head.orig.dst.v4 = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_repl_ipv4_src(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->repl.src.v4 = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_repl_ipv4_dst(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->repl.dst.v4 = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_orig_ipv6_src(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| memcpy(&ct->head.orig.src.v6, value, sizeof(uint32_t)*4); |
| } |
| |
| static void |
| set_attr_orig_ipv6_dst(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| memcpy(&ct->head.orig.dst.v6, value, sizeof(uint32_t)*4); |
| } |
| |
| static void |
| set_attr_repl_ipv6_src(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| memcpy(&ct->repl.src.v6, value, sizeof(uint32_t)*4); |
| } |
| |
| static void |
| set_attr_repl_ipv6_dst(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| memcpy(&ct->repl.dst.v6, value, sizeof(uint32_t)*4); |
| } |
| |
| static void |
| set_attr_orig_port_src(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->head.orig.l4src.all = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_orig_port_dst(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->head.orig.l4dst.all = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_repl_port_src(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->repl.l4src.all = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_repl_port_dst(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->repl.l4dst.all = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_orig_zone(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->head.orig.zone = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_repl_zone(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->repl.zone = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_icmp_type(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| uint8_t rtype; |
| |
| ct->head.orig.l4dst.icmp.type = *((uint8_t *) value); |
| |
| switch(ct->head.orig.l3protonum) { |
| case AF_INET: |
| rtype = invmap_icmp[*((uint8_t *) value)]; |
| break; |
| |
| case AF_INET6: |
| rtype = invmap_icmpv6[*((uint8_t *) value) - 128]; |
| break; |
| |
| default: |
| rtype = 0; /* not found */ |
| } |
| |
| if (rtype) |
| ct->repl.l4dst.icmp.type = rtype - 1; |
| else |
| ct->repl.l4dst.icmp.type = 255; /* will fail with -EINVAL */ |
| |
| } |
| |
| static void |
| set_attr_icmp_code(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->head.orig.l4dst.icmp.code = *((uint8_t *) value); |
| ct->repl.l4dst.icmp.code = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_icmp_id(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->head.orig.l4src.icmp.id = *((uint16_t *) value); |
| ct->repl.l4src.icmp.id = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_orig_l3proto(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->head.orig.l3protonum = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_repl_l3proto(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->repl.l3protonum = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_orig_l4proto(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->head.orig.protonum = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_repl_l4proto(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->repl.protonum = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_tcp_state(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.tcp.state = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_tcp_flags_orig(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.tcp.flags[__DIR_ORIG].value = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_tcp_mask_orig(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.tcp.flags[__DIR_ORIG].mask = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_tcp_flags_repl(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.tcp.flags[__DIR_REPL].value = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_tcp_mask_repl(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.tcp.flags[__DIR_REPL].mask = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_sctp_state(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.sctp.state = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_sctp_vtag_orig(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.sctp.vtag[__DIR_ORIG] = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_sctp_vtag_repl(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.sctp.vtag[__DIR_REPL] = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_snat_ipv4(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->snat.min_ip.v4 = ct->snat.max_ip.v4 = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_dnat_ipv4(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->dnat.min_ip.v4 = ct->dnat.max_ip.v4 = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_snat_ipv6(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| memcpy(&ct->snat.min_ip.v6, value, sizeof(struct in6_addr)); |
| memcpy(&ct->snat.max_ip.v6, value, sizeof(struct in6_addr)); |
| } |
| |
| static void |
| set_attr_dnat_ipv6(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| memcpy(&ct->dnat.min_ip.v6, value, sizeof(struct in6_addr)); |
| memcpy(&ct->dnat.max_ip.v6, value, sizeof(struct in6_addr)); |
| } |
| |
| static void |
| set_attr_snat_port(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->snat.l4min.all = ct->snat.l4max.all = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_dnat_port(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->dnat.l4min.all = ct->dnat.l4max.all = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_timeout(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->timeout = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_mark(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->mark = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_secmark(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->secmark = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_status(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->status = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_id(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->id = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_master_ipv4_src(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->master.src.v4 = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_master_ipv4_dst(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->master.dst.v4 = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_master_ipv6_src(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| memcpy(&ct->master.src.v6, value, sizeof(uint32_t)*4); |
| } |
| |
| static void |
| set_attr_master_ipv6_dst(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| memcpy(&ct->master.dst.v6, value, sizeof(uint32_t)*4); |
| } |
| |
| static void |
| set_attr_master_port_src(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->master.l4src.all = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_master_port_dst(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->master.l4dst.all = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_master_l3proto(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->master.l3protonum = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_master_l4proto(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->master.protonum = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_orig_cor_pos(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->natseq[__DIR_ORIG].correction_pos = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_orig_off_bfr(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->natseq[__DIR_ORIG].offset_before = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_orig_off_aft(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->natseq[__DIR_ORIG].offset_after = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_repl_cor_pos(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->natseq[__DIR_REPL].correction_pos = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_repl_off_bfr(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->natseq[__DIR_REPL].offset_before = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_repl_off_aft(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->natseq[__DIR_REPL].offset_after = *((uint32_t *) value); |
| } |
| |
| static void |
| set_attr_helper_name(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| strncpy(ct->helper_name, value, NFCT_HELPER_NAME_MAX); |
| ct->helper_name[NFCT_HELPER_NAME_MAX-1] = '\0'; |
| } |
| |
| static void |
| set_attr_dccp_state(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.dccp.state = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_dccp_role(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.dccp.role = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_dccp_handshake_seq(struct nf_conntrack *ct, const void *value, |
| size_t len) |
| { |
| ct->protoinfo.dccp.handshake_seq = *((uint64_t *) value); |
| } |
| |
| static void |
| set_attr_tcp_wscale_orig(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.tcp.wscale[__DIR_ORIG] = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_tcp_wscale_repl(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->protoinfo.tcp.wscale[__DIR_REPL] = *((uint8_t *) value); |
| } |
| |
| static void |
| set_attr_zone(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| ct->zone = *((uint16_t *) value); |
| } |
| |
| static void |
| set_attr_helper_info(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| if (ct->helper_info == NULL) { |
| retry: |
| ct->helper_info = calloc(1, len); |
| if (ct->helper_info == NULL) |
| return; |
| |
| memcpy(ct->helper_info, value, len); |
| } else { |
| free(ct->helper_info); |
| goto retry; |
| } |
| } |
| |
| static void |
| do_set_attr_connlabels(struct nfct_bitmask *current, const void *value) |
| { |
| if (current && current != value) |
| nfct_bitmask_destroy(current); |
| } |
| |
| static void |
| set_attr_connlabels(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| do_set_attr_connlabels(ct->connlabels, value); |
| ct->connlabels = (void *) value; |
| } |
| |
| static void |
| set_attr_connlabels_mask(struct nf_conntrack *ct, const void *value, size_t len) |
| { |
| do_set_attr_connlabels(ct->connlabels_mask, value); |
| ct->connlabels_mask = (void *) value; |
| } |
| |
| static void |
| set_attr_do_nothing(struct nf_conntrack *ct, const void *value, size_t len) {} |
| |
| const set_attr set_attr_array[ATTR_MAX] = { |
| [ATTR_ORIG_IPV4_SRC] = set_attr_orig_ipv4_src, |
| [ATTR_ORIG_IPV4_DST] = set_attr_orig_ipv4_dst, |
| [ATTR_REPL_IPV4_SRC] = set_attr_repl_ipv4_src, |
| [ATTR_REPL_IPV4_DST] = set_attr_repl_ipv4_dst, |
| [ATTR_ORIG_IPV6_SRC] = set_attr_orig_ipv6_src, |
| [ATTR_ORIG_IPV6_DST] = set_attr_orig_ipv6_dst, |
| [ATTR_REPL_IPV6_SRC] = set_attr_repl_ipv6_src, |
| [ATTR_REPL_IPV6_DST] = set_attr_repl_ipv6_dst, |
| [ATTR_ORIG_PORT_SRC] = set_attr_orig_port_src, |
| [ATTR_ORIG_PORT_DST] = set_attr_orig_port_dst, |
| [ATTR_REPL_PORT_SRC] = set_attr_repl_port_src, |
| [ATTR_REPL_PORT_DST] = set_attr_repl_port_dst, |
| [ATTR_ICMP_TYPE] = set_attr_icmp_type, |
| [ATTR_ICMP_CODE] = set_attr_icmp_code, |
| [ATTR_ICMP_ID] = set_attr_icmp_id, |
| [ATTR_ORIG_L3PROTO] = set_attr_orig_l3proto, |
| [ATTR_REPL_L3PROTO] = set_attr_repl_l3proto, |
| [ATTR_ORIG_L4PROTO] = set_attr_orig_l4proto, |
| [ATTR_REPL_L4PROTO] = set_attr_repl_l4proto, |
| [ATTR_TCP_STATE] = set_attr_tcp_state, |
| [ATTR_SNAT_IPV4] = set_attr_snat_ipv4, |
| [ATTR_DNAT_IPV4] = set_attr_dnat_ipv4, |
| [ATTR_SNAT_PORT] = set_attr_snat_port, |
| [ATTR_DNAT_PORT] = set_attr_dnat_port, |
| [ATTR_TIMEOUT] = set_attr_timeout, |
| [ATTR_MARK] = set_attr_mark, |
| [ATTR_ORIG_COUNTER_PACKETS] = set_attr_do_nothing, |
| [ATTR_REPL_COUNTER_PACKETS] = set_attr_do_nothing, |
| [ATTR_ORIG_COUNTER_BYTES] = set_attr_do_nothing, |
| [ATTR_REPL_COUNTER_BYTES] = set_attr_do_nothing, |
| [ATTR_USE] = set_attr_do_nothing, |
| [ATTR_ID] = set_attr_id, |
| [ATTR_STATUS] = set_attr_status, |
| [ATTR_TCP_FLAGS_ORIG] = set_attr_tcp_flags_orig, |
| [ATTR_TCP_FLAGS_REPL] = set_attr_tcp_flags_repl, |
| [ATTR_TCP_MASK_ORIG] = set_attr_tcp_mask_orig, |
| [ATTR_TCP_MASK_REPL] = set_attr_tcp_mask_repl, |
| [ATTR_MASTER_IPV4_SRC] = set_attr_master_ipv4_src, |
| [ATTR_MASTER_IPV4_DST] = set_attr_master_ipv4_dst, |
| [ATTR_MASTER_IPV6_SRC] = set_attr_master_ipv6_src, |
| [ATTR_MASTER_IPV6_DST] = set_attr_master_ipv6_dst, |
| [ATTR_MASTER_PORT_SRC] = set_attr_master_port_src, |
| [ATTR_MASTER_PORT_DST] = set_attr_master_port_dst, |
| [ATTR_MASTER_L3PROTO] = set_attr_master_l3proto, |
| [ATTR_MASTER_L4PROTO] = set_attr_master_l4proto, |
| [ATTR_SECMARK] = set_attr_secmark, |
| [ATTR_ORIG_NAT_SEQ_CORRECTION_POS] = set_attr_orig_cor_pos, |
| [ATTR_ORIG_NAT_SEQ_OFFSET_BEFORE] = set_attr_orig_off_bfr, |
| [ATTR_ORIG_NAT_SEQ_OFFSET_AFTER] = set_attr_orig_off_aft, |
| [ATTR_REPL_NAT_SEQ_CORRECTION_POS] = set_attr_repl_cor_pos, |
| [ATTR_REPL_NAT_SEQ_OFFSET_BEFORE] = set_attr_repl_off_bfr, |
| [ATTR_REPL_NAT_SEQ_OFFSET_AFTER] = set_attr_repl_off_aft, |
| [ATTR_SCTP_STATE] = set_attr_sctp_state, |
| [ATTR_SCTP_VTAG_ORIG] = set_attr_sctp_vtag_orig, |
| [ATTR_SCTP_VTAG_REPL] = set_attr_sctp_vtag_repl, |
| [ATTR_HELPER_NAME] = set_attr_helper_name, |
| [ATTR_DCCP_STATE] = set_attr_dccp_state, |
| [ATTR_DCCP_ROLE] = set_attr_dccp_role, |
| [ATTR_DCCP_HANDSHAKE_SEQ] = set_attr_dccp_handshake_seq, |
| [ATTR_TCP_WSCALE_ORIG] = set_attr_tcp_wscale_orig, |
| [ATTR_TCP_WSCALE_REPL] = set_attr_tcp_wscale_repl, |
| [ATTR_ZONE] = set_attr_zone, |
| [ATTR_ORIG_ZONE] = set_attr_orig_zone, |
| [ATTR_REPL_ZONE] = set_attr_repl_zone, |
| [ATTR_SECCTX] = set_attr_do_nothing, |
| [ATTR_TIMESTAMP_START] = set_attr_do_nothing, |
| [ATTR_TIMESTAMP_STOP] = set_attr_do_nothing, |
| [ATTR_HELPER_INFO] = set_attr_helper_info, |
| [ATTR_CONNLABELS] = set_attr_connlabels, |
| [ATTR_CONNLABELS_MASK] = set_attr_connlabels_mask, |
| [ATTR_SNAT_IPV6] = set_attr_snat_ipv6, |
| [ATTR_DNAT_IPV6] = set_attr_dnat_ipv6, |
| }; |