static int ebt_among_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { const struct ebt_among_info *info = data; int expected_length = sizeof(struct ebt_among_info); const struct ebt_mac_wormhash *wh_dst, *wh_src; int err; wh_dst = ebt_among_wh_dst(info); wh_src = ebt_among_wh_src(info); expected_length += ebt_mac_wormhash_size(wh_dst); expected_length += ebt_mac_wormhash_size(wh_src); if (datalen != EBT_ALIGN(expected_length)) { printk(KERN_WARNING "ebtables: among: wrong size: %d " "against expected %d, rounded to %Zd\n", datalen, expected_length, EBT_ALIGN(expected_length)); return -EINVAL; } if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) { printk(KERN_WARNING "ebtables: among: dst integrity fail: %x\n", -err); return -EINVAL; } if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) { printk(KERN_WARNING "ebtables: among: src integrity fail: %x\n", -err); return -EINVAL; } return 0; }
static int ebt_among_mt_check(const struct xt_mtchk_param *par) { const struct ebt_among_info *info = par->matchinfo; const struct ebt_entry_match *em = container_of(par->matchinfo, const struct ebt_entry_match, data); int expected_length = sizeof(struct ebt_among_info); const struct ebt_mac_wormhash *wh_dst, *wh_src; int err; wh_dst = ebt_among_wh_dst(info); wh_src = ebt_among_wh_src(info); expected_length += ebt_mac_wormhash_size(wh_dst); expected_length += ebt_mac_wormhash_size(wh_src); if (em->match_size != EBT_ALIGN(expected_length)) { pr_info("wrong size: %d against expected %d, rounded to %Zd\n", em->match_size, expected_length, EBT_ALIGN(expected_length)); return -EINVAL; } if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) { pr_info("dst integrity fail: %x\n", -err); return -EINVAL; } if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) { pr_info("src integrity fail: %x\n", -err); return -EINVAL; } return 0; }
static bool ebt_among_mt_check(const struct xt_mtchk_param *par) { const struct ebt_among_info *info = par->matchinfo; const struct ebt_entry_match *em = container_of(par->matchinfo, const struct ebt_entry_match, data); int expected_length = sizeof(struct ebt_among_info); const struct ebt_mac_wormhash *wh_dst, *wh_src; int err; wh_dst = ebt_among_wh_dst(info); wh_src = ebt_among_wh_src(info); expected_length += ebt_mac_wormhash_size(wh_dst); expected_length += ebt_mac_wormhash_size(wh_src); if (em->match_size != EBT_ALIGN(expected_length)) { printk(KERN_WARNING "ebtables: among: wrong size: %d " "against expected %d, rounded to %Zd\n", em->match_size, expected_length, EBT_ALIGN(expected_length)); return false; } if (wh_dst && (err = ebt_mac_wormhash_check_integrity(wh_dst))) { printk(KERN_WARNING "ebtables: among: dst integrity fail: %x\n", -err); return false; } if (wh_src && (err = ebt_mac_wormhash_check_integrity(wh_src))) { printk(KERN_WARNING "ebtables: among: src integrity fail: %x\n", -err); return false; } return true; }
static int ebt_ip_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_ip_info *info = (struct ebt_ip_info *)data; if (datalen != EBT_ALIGN(sizeof(struct ebt_ip_info))) return -EINVAL; if (e->ethproto != __constant_htons(ETH_P_IP) || e->invflags & EBT_IPROTO) return -EINVAL; if (info->bitmask & ~EBT_IP_MASK || info->invflags & ~EBT_IP_MASK) return -EINVAL; if (info->bitmask & (EBT_IP_DPORT | EBT_IP_SPORT)) { if (!info->bitmask & EBT_IPROTO) return -EINVAL; if (info->protocol != IPPROTO_TCP && info->protocol != IPPROTO_UDP) return -EINVAL; } if (info->bitmask & EBT_IP_DPORT && info->dport[0] > info->dport[1]) return -EINVAL; if (info->bitmask & EBT_IP_SPORT && info->sport[0] > info->sport[1]) return -EINVAL; return 0; }
static int ebt_pkttype_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data; if (datalen != EBT_ALIGN(sizeof(struct ebt_pkttype_info))) return -EINVAL; if (info->invert != 0 && info->invert != 1) return -EINVAL; /* Allow any pkt_type value */ return 0; }
static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data; if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info))) return -EINVAL; if (BASE_CHAIN && info->target == EBT_RETURN) return -EINVAL; CLEAR_BASE_CHAIN_BIT; if (INVALID_TARGET) return -EINVAL; return 0; }
static int ebt_log_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_log_info *info = (struct ebt_log_info *)data; if (datalen != EBT_ALIGN(sizeof(struct ebt_log_info))) return -EINVAL; if (info->bitmask & ~EBT_LOG_MASK) return -EINVAL; if (info->loglevel >= 8) return -EINVAL; info->prefix[EBT_LOG_PREFIX_SIZE - 1] = '\0'; return 0; }
static int ebt_arp_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { const struct ebt_arp_info *info = data; if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info))) return -EINVAL; if ((e->ethproto != htons(ETH_P_ARP) && e->ethproto != htons(ETH_P_RARP)) || e->invflags & EBT_IPROTO) return -EINVAL; if (info->bitmask & ~EBT_ARP_MASK || info->invflags & ~EBT_ARP_MASK) return -EINVAL; return 0; }
static int ebt_ulog_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_ulog_info *uloginfo = (struct ebt_ulog_info *)data; if (datalen != EBT_ALIGN(sizeof(struct ebt_ulog_info)) || uloginfo->nlgroup > 31) return -EINVAL; uloginfo->prefix[EBT_ULOG_PREFIX_LEN - 1] = '\0'; if (uloginfo->qthreshold > EBT_ULOG_MAX_QLEN) uloginfo->qthreshold = EBT_ULOG_MAX_QLEN; return 0; }
static int ebt_target_reply_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { const struct ebt_arpreply_info *info = data; if (datalen != EBT_ALIGN(sizeof(struct ebt_arpreply_info))) return -EINVAL; if (BASE_CHAIN && info->target == EBT_RETURN) return -EINVAL; if (e->ethproto != htons(ETH_P_ARP) || e->invflags & EBT_IPROTO) return -EINVAL; CLEAR_BASE_CHAIN_BIT; if (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) return -EINVAL; return 0; }
static int ebt_target_redirect_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_redirect_info *info = (struct ebt_redirect_info *)data; if (datalen != EBT_ALIGN(sizeof(struct ebt_redirect_info))) return -EINVAL; if (BASE_CHAIN && info->target == EBT_RETURN) return -EINVAL; CLEAR_BASE_CHAIN_BIT; if ( (strcmp(tablename, "nat") || hookmask & ~(1 << NF_BR_PRE_ROUTING)) && (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) return -EINVAL; if (INVALID_TARGET) return -EINVAL; return 0; }
static int ebt_stp_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_stp_info *info = (struct ebt_stp_info *)data; int len = EBT_ALIGN(sizeof(struct ebt_stp_info)); uint8_t bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 }; uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; if (info->bitmask & ~EBT_STP_MASK || info->invflags & ~EBT_STP_MASK || !(info->bitmask & EBT_STP_MASK)) return -EINVAL; if (datalen != len) return -EINVAL; /* Make sure the match only receives stp frames */ if (compare_ether_addr(e->destmac, bridge_ula) || compare_ether_addr(e->destmsk, msk) || !(e->bitmask & EBT_DESTMAC)) return -EINVAL; return 0; }
static int ebt_limit_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_limit_info *info = data; if (datalen != EBT_ALIGN(sizeof(struct ebt_limit_info))) return -EINVAL; /* Check for overflow. */ if (info->burst == 0 || user2credits(info->avg * info->burst) < user2credits(info->avg)) { printk("Overflow in ebt_limit, try lower: %u/%u\n", info->avg, info->burst); return -EINVAL; } /* User avg in seconds * EBT_LIMIT_SCALE: convert to jiffies * 128. */ info->prev = jiffies; info->credit = user2credits(info->avg * info->burst); info->credit_cap = user2credits(info->avg * info->burst); info->cost = user2credits(info->avg); return 0; }
static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, const struct ebt_entry *e, void *data, unsigned int datalen) { const struct ebt_nat_info *info = data; int tmp; if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info))) return -EINVAL; tmp = info->target | ~EBT_VERDICT_BITS; if (BASE_CHAIN && tmp == EBT_RETURN) return -EINVAL; CLEAR_BASE_CHAIN_BIT; if (strcmp(tablename, "nat")) return -EINVAL; if (hookmask & ~(1 << NF_BR_POST_ROUTING)) return -EINVAL; if (tmp < -NUM_STANDARD_TARGETS || tmp >= 0) return -EINVAL; tmp = info->target | EBT_VERDICT_BITS; if ((tmp & ~NAT_ARP_BIT) != ~NAT_ARP_BIT) return -EINVAL; return 0; }
static int ebt_target_vlan_check(const char *tablename, unsigned int hooknr, const struct ebt_entry *e, void *data, unsigned int datalen) { struct ebt_vlan_t_info *info = (struct ebt_vlan_t_info *) data; /* Parameters buffer overflow check */ if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_t_info))) { DEBUG_MSG ("passed size %d is not eq to ebt_vlan_info (%Zd)\n", datalen, sizeof(struct ebt_vlan_t_info)); return -EINVAL; } /* Is it 802.1Q frame checked? */ if (e->ethproto != __constant_htons(ETH_P_8021Q)) { DEBUG_MSG ("passed entry proto %2.4X is not 802.1Q (8100)\n", (unsigned short) ntohs(e->ethproto)); return -EINVAL; } /* Check for bitmask range * True if even one bit is out of mask */ if (info->bitmask & ~EBT_VLAN_TARGET_MASK) { DEBUG_MSG("bitmask %2X is out of mask (%2X)\n", info->bitmask, EBT_VLAN_TARGET_MASK); return -EINVAL; } /* Reserved VLAN ID (VID) values * ----------------------------- * 0 - The null VLAN ID. * 1 - The default Port VID (PVID) * 0x0FFF - Reserved for implementation use. * if_vlan.h: VLAN_GROUP_ARRAY_LEN 4096. */ if (GET_BITMASK(EBT_VLAN_TARGET_ID)) { if (!!info->id) { /* if id!=0 => check vid range */ if (info->id > VLAN_GROUP_ARRAY_LEN) { DEBUG_MSG ("id %d is out of range (1-4094)\n", info->id); return -EINVAL; } #if 0 /* Note: This is valid VLAN-tagged frame point. * Any value of user_priority are acceptable, * but should be ignored according to 802.1Q Std. * So we just drop the prio flag. */ info->bitmask &= ~EBT_VLAN_TARGET_PRIO; #endif } #if 0 /*w00135358 -- VLAN ID == 0 is OK for VLAN ID Remark -- 20080928 */ else { return -EINVAL; } #endif } if (GET_BITMASK(EBT_VLAN_TARGET_PRIO)) { if ((unsigned char) info->prio > 7) { DEBUG_MSG("prio %d is out of range (0-7)\n", info->prio); return -EINVAL; } } return 0; }
static int parse(int c, char **argv, int argc, const struct ebt_u_entry *entry, unsigned int *flags, struct ebt_entry_match **match) { struct ebt_among_info *info = (struct ebt_among_info *) (*match)->data; struct ebt_mac_wormhash *wh; struct ebt_entry_match *h; int new_size; long flen; int fd; switch (c) { case AMONG_DST_F: case AMONG_SRC_F: case AMONG_DST: case AMONG_SRC: if (c == AMONG_DST || c == AMONG_DST_F) { ebt_check_option2(flags, OPT_DST); } else { ebt_check_option2(flags, OPT_SRC); } if (ebt_check_inverse2(optarg)) { if (c == AMONG_DST || c == AMONG_DST_F) info->bitmask |= EBT_AMONG_DST_NEG; else info->bitmask |= EBT_AMONG_SRC_NEG; } if (c == AMONG_DST_F || c == AMONG_SRC_F) { struct stat stats; if ((fd = open(optarg, O_RDONLY)) == -1) ebt_print_error("Couldn't open file '%s'", optarg); fstat(fd, &stats); flen = stats.st_size; /* use mmap because the file will probably be big */ optarg = mmap(0, flen, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (optarg == MAP_FAILED) ebt_print_error("Couldn't map file to memory"); if (optarg[flen-1] != '\n') ebt_print_error("File should end with a newline"); if (strchr(optarg, '\n') != optarg+flen-1) ebt_print_error("File should only contain one line"); optarg[flen-1] = '\0'; if (ebt_errormsg[0] != '\0') { munmap(argv, flen); close(fd); exit(-1); } } wh = create_wormhash(optarg); if (ebt_errormsg[0] != '\0') break; new_size = old_size+ebt_mac_wormhash_size(wh); h = malloc(sizeof(struct ebt_entry_match)+EBT_ALIGN(new_size)); if (!h) ebt_print_memory(); memcpy(h, *match, old_size+sizeof(struct ebt_entry_match)); memcpy((char *)h+old_size+sizeof(struct ebt_entry_match), wh, ebt_mac_wormhash_size(wh)); h->match_size = EBT_ALIGN(new_size); info = (struct ebt_among_info *) h->data; if (c == AMONG_DST) { info->wh_dst_ofs = old_size; } else { info->wh_src_ofs = old_size; } old_size = new_size; free(*match); *match = h; free(wh); if (c == AMONG_DST_F || c == AMONG_SRC_F) { munmap(argv, flen); close(fd); } break; default: return 0; } return 1; }