1 #include <stdio.h> 2 #include <xtables.h> 3 #include <linux/netfilter_ipv6/ip6t_frag.h> 4 5 enum { 6 O_FRAGID = 0, 7 O_FRAGLEN, 8 O_FRAGRES, 9 O_FRAGFIRST, 10 O_FRAGMORE, 11 O_FRAGLAST, 12 F_FRAGMORE = 1 << O_FRAGMORE, 13 F_FRAGLAST = 1 << O_FRAGLAST, 14 }; 15 16 static void frag_help(void) 17 { 18 printf( 19 "frag match options:\n" 20 "[!] --fragid id[:id] match the id (range)\n" 21 "[!] --fraglen length total length of this header\n" 22 " --fragres check the reserved field too\n" 23 " --fragfirst matches on the first fragment\n" 24 " [--fragmore|--fraglast] there are more fragments or this\n" 25 " is the last one\n"); 26 } 27 28 #define s struct ip6t_frag 29 static const struct xt_option_entry frag_opts[] = { 30 {.name = "fragid", .id = O_FRAGID, .type = XTTYPE_UINT32RC, 31 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, ids)}, 32 {.name = "fraglen", .id = O_FRAGLEN, .type = XTTYPE_UINT32, 33 .flags = XTOPT_INVERT | XTOPT_PUT, XTOPT_POINTER(s, hdrlen)}, 34 {.name = "fragres", .id = O_FRAGRES, .type = XTTYPE_NONE}, 35 {.name = "fragfirst", .id = O_FRAGFIRST, .type = XTTYPE_NONE}, 36 {.name = "fragmore", .id = O_FRAGMORE, .type = XTTYPE_NONE, 37 .excl = F_FRAGLAST}, 38 {.name = "fraglast", .id = O_FRAGLAST, .type = XTTYPE_NONE, 39 .excl = F_FRAGMORE}, 40 XTOPT_TABLEEND, 41 }; 42 #undef s 43 44 static void frag_init(struct xt_entry_match *m) 45 { 46 struct ip6t_frag *fraginfo = (void *)m->data; 47 48 fraginfo->ids[1] = ~0U; 49 } 50 51 static void frag_parse(struct xt_option_call *cb) 52 { 53 struct ip6t_frag *fraginfo = cb->data; 54 55 xtables_option_parse(cb); 56 switch (cb->entry->id) { 57 case O_FRAGID: 58 if (cb->nvals == 1) 59 fraginfo->ids[1] = fraginfo->ids[0]; 60 if (cb->invert) 61 fraginfo->invflags |= IP6T_FRAG_INV_IDS; 62 /* 63 * Note however that IP6T_FRAG_IDS is not tested by anything, 64 * so it is merely here for completeness. 65 */ 66 fraginfo->flags |= IP6T_FRAG_IDS; 67 break; 68 case O_FRAGLEN: 69 /* 70 * As of Linux 3.0, the kernel does not check for 71 * fraglen at all. 72 */ 73 if (cb->invert) 74 fraginfo->invflags |= IP6T_FRAG_INV_LEN; 75 fraginfo->flags |= IP6T_FRAG_LEN; 76 break; 77 case O_FRAGRES: 78 fraginfo->flags |= IP6T_FRAG_RES; 79 break; 80 case O_FRAGFIRST: 81 fraginfo->flags |= IP6T_FRAG_FST; 82 break; 83 case O_FRAGMORE: 84 fraginfo->flags |= IP6T_FRAG_MF; 85 break; 86 case O_FRAGLAST: 87 fraginfo->flags |= IP6T_FRAG_NMF; 88 break; 89 } 90 } 91 92 static void 93 print_ids(const char *name, uint32_t min, uint32_t max, 94 int invert) 95 { 96 const char *inv = invert ? "!" : ""; 97 98 if (min != 0 || max != 0xFFFFFFFF || invert) { 99 printf("%s", name); 100 if (min == max) 101 printf(":%s%u", inv, min); 102 else 103 printf("s:%s%u:%u", inv, min, max); 104 } 105 } 106 107 static void frag_print(const void *ip, const struct xt_entry_match *match, 108 int numeric) 109 { 110 const struct ip6t_frag *frag = (struct ip6t_frag *)match->data; 111 112 printf(" frag "); 113 print_ids("id", frag->ids[0], frag->ids[1], 114 frag->invflags & IP6T_FRAG_INV_IDS); 115 116 if (frag->flags & IP6T_FRAG_LEN) { 117 printf(" length:%s%u", 118 frag->invflags & IP6T_FRAG_INV_LEN ? "!" : "", 119 frag->hdrlen); 120 } 121 122 if (frag->flags & IP6T_FRAG_RES) 123 printf(" reserved"); 124 125 if (frag->flags & IP6T_FRAG_FST) 126 printf(" first"); 127 128 if (frag->flags & IP6T_FRAG_MF) 129 printf(" more"); 130 131 if (frag->flags & IP6T_FRAG_NMF) 132 printf(" last"); 133 134 if (frag->invflags & ~IP6T_FRAG_INV_MASK) 135 printf(" Unknown invflags: 0x%X", 136 frag->invflags & ~IP6T_FRAG_INV_MASK); 137 } 138 139 static void frag_save(const void *ip, const struct xt_entry_match *match) 140 { 141 const struct ip6t_frag *fraginfo = (struct ip6t_frag *)match->data; 142 143 if (!(fraginfo->ids[0] == 0 144 && fraginfo->ids[1] == 0xFFFFFFFF)) { 145 printf("%s --fragid ", 146 (fraginfo->invflags & IP6T_FRAG_INV_IDS) ? " !" : ""); 147 if (fraginfo->ids[0] 148 != fraginfo->ids[1]) 149 printf("%u:%u", 150 fraginfo->ids[0], 151 fraginfo->ids[1]); 152 else 153 printf("%u", 154 fraginfo->ids[0]); 155 } 156 157 if (fraginfo->flags & IP6T_FRAG_LEN) { 158 printf("%s --fraglen %u", 159 (fraginfo->invflags & IP6T_FRAG_INV_LEN) ? " !" : "", 160 fraginfo->hdrlen); 161 } 162 163 if (fraginfo->flags & IP6T_FRAG_RES) 164 printf(" --fragres"); 165 166 if (fraginfo->flags & IP6T_FRAG_FST) 167 printf(" --fragfirst"); 168 169 if (fraginfo->flags & IP6T_FRAG_MF) 170 printf(" --fragmore"); 171 172 if (fraginfo->flags & IP6T_FRAG_NMF) 173 printf(" --fraglast"); 174 } 175 176 static struct xtables_match frag_mt6_reg = { 177 .name = "frag", 178 .version = XTABLES_VERSION, 179 .family = NFPROTO_IPV6, 180 .size = XT_ALIGN(sizeof(struct ip6t_frag)), 181 .userspacesize = XT_ALIGN(sizeof(struct ip6t_frag)), 182 .help = frag_help, 183 .init = frag_init, 184 .print = frag_print, 185 .save = frag_save, 186 .x6_parse = frag_parse, 187 .x6_options = frag_opts, 188 }; 189 190 void 191 _init(void) 192 { 193 xtables_register_match(&frag_mt6_reg); 194 } 195