Main Page | Class List | File List | Class Members | File Members

ipt_REJECT.c

Go to the documentation of this file.
00001 /* 00002 * This is a module which is used for rejecting packets. 00003 * Added support for customized reject packets (Jozsef Kadlecsik). 00004 * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812] 00005 */ 00006 #include <linux/config.h> 00007 #include <linux/module.h> 00008 #include <linux/skbuff.h> 00009 #include <linux/ip.h> 00010 #include <linux/udp.h> 00011 #include <linux/icmp.h> 00012 #include <net/icmp.h> 00013 #include <net/ip.h> 00014 #include <net/tcp.h> 00015 #include <net/route.h> 00016 #include <linux/netfilter_ipv4/ip_tables.h> 00017 #include <linux/netfilter_ipv4/ipt_REJECT.h> 00018 00019 #if 0 00020 #define DEBUGP printk 00021 #else 00022 #define DEBUGP(format, args...) 00023 #endif 00024 00025 /* If the original packet is part of a connection, but the connection 00026 is not confirmed, our manufactured reply will not be associated 00027 with it, so we need to do this manually. */ 00028 static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct) 00029 { 00030 void (*attach)(struct sk_buff *, struct nf_ct_info *); 00031 00032 /* Avoid module unload race with ip_ct_attach being NULLed out */ 00033 if (nfct && (attach = ip_ct_attach) != NULL) 00034 attach(new_skb, nfct); 00035 } 00036 00037 static inline struct rtable *route_reverse(struct sk_buff *skb, int hook) 00038 { 00039 struct iphdr *iph = skb->nh.iph; 00040 struct dst_entry *odst; 00041 struct rt_key key = {}; 00042 struct rtable *rt; 00043 00044 if (hook != NF_IP_FORWARD) { 00045 key.dst = iph->saddr; 00046 if (hook == NF_IP_LOCAL_IN) 00047 key.src = iph->daddr; 00048 key.tos = RT_TOS(iph->tos); 00049 00050 if (ip_route_output_key(&rt, &key) != 0) 00051 return NULL; 00052 } else { 00053 /* non-local src, find valid iif to satisfy 00054 * rp-filter when calling ip_route_input. */ 00055 key.dst = iph->daddr; 00056 if (ip_route_output_key(&rt, &key) != 0) 00057 return NULL; 00058 00059 odst = skb->dst; 00060 if (ip_route_input(skb, iph->saddr, iph->daddr, 00061 RT_TOS(iph->tos), rt->u.dst.dev) != 0) { 00062 dst_release(&rt->u.dst); 00063 return NULL; 00064 } 00065 dst_release(&rt->u.dst); 00066 rt = (struct rtable *)skb->dst; 00067 skb->dst = odst; 00068 } 00069 00070 if (rt->u.dst.error) { 00071 dst_release(&rt->u.dst); 00072 rt = NULL; 00073 } 00074 00075 return rt; 00076 } 00077 00078 /* Send RST reply */ 00079 static void send_reset(struct sk_buff *oldskb, int hook) 00080 { 00081 struct sk_buff *nskb; 00082 struct tcphdr *otcph, *tcph; 00083 struct rtable *rt; 00084 unsigned int otcplen; 00085 u_int16_t tmp_port; 00086 u_int32_t tmp_addr; 00087 int needs_ack; 00088 int hh_len; 00089 00090 /* IP header checks: fragment, too short. */ 00091 if (oldskb->nh.iph->frag_off & htons(IP_OFFSET) 00092 || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr)) 00093 return; 00094 00095 otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl); 00096 otcplen = oldskb->len - oldskb->nh.iph->ihl*4; 00097 00098 /* No RST for RST. */ 00099 if (otcph->rst) 00100 return; 00101 00102 /* Check checksum. */ 00103 if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr, 00104 oldskb->nh.iph->daddr, 00105 csum_partial((char *)otcph, otcplen, 0)) != 0) 00106 return; 00107 00108 if ((rt = route_reverse(oldskb, hook)) == NULL) 00109 return; 00110 00111 hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; 00112 00113 00114 /* Copy skb (even if skb is about to be dropped, we can't just 00115 clone it because there may be other things, such as tcpdump, 00116 interested in it). We also need to expand headroom in case 00117 hh_len of incoming interface < hh_len of outgoing interface */ 00118 nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb), 00119 GFP_ATOMIC); 00120 if (!nskb) { 00121 dst_release(&rt->u.dst); 00122 return; 00123 } 00124 00125 dst_release(nskb->dst); 00126 nskb->dst = &rt->u.dst; 00127 00128 /* This packet will not be the same as the other: clear nf fields */ 00129 nf_conntrack_put(nskb->nfct); 00130 nskb->nfct = NULL; 00131 nskb->nfcache = 0; 00132 #ifdef CONFIG_NETFILTER_DEBUG 00133 nskb->nf_debug = 0; 00134 #endif 00135 nskb->nfmark = 0; 00136 00137 tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl); 00138 00139 /* Swap source and dest */ 00140 tmp_addr = nskb->nh.iph->saddr; 00141 nskb->nh.iph->saddr = nskb->nh.iph->daddr; 00142 nskb->nh.iph->daddr = tmp_addr; 00143 tmp_port = tcph->source; 00144 tcph->source = tcph->dest; 00145 tcph->dest = tmp_port; 00146 00147 /* Truncate to length (no data) */ 00148 tcph->doff = sizeof(struct tcphdr)/4; 00149 skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr)); 00150 nskb->nh.iph->tot_len = htons(nskb->len); 00151 00152 if (tcph->ack) { 00153 needs_ack = 0; 00154 tcph->seq = otcph->ack_seq; 00155 tcph->ack_seq = 0; 00156 } else { 00157 needs_ack = 1; 00158 tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin 00159 + otcplen - (otcph->doff<<2)); 00160 tcph->seq = 0; 00161 } 00162 00163 /* Reset flags */ 00164 ((u_int8_t *)tcph)[13] = 0; 00165 tcph->rst = 1; 00166 tcph->ack = needs_ack; 00167 00168 tcph->window = 0; 00169 tcph->urg_ptr = 0; 00170 00171 /* Adjust TCP checksum */ 00172 tcph->check = 0; 00173 tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr), 00174 nskb->nh.iph->saddr, 00175 nskb->nh.iph->daddr, 00176 csum_partial((char *)tcph, 00177 sizeof(struct tcphdr), 0)); 00178 00179 /* Adjust IP TTL, DF */ 00180 nskb->nh.iph->ttl = MAXTTL; 00181 /* Set DF, id = 0 */ 00182 nskb->nh.iph->frag_off = htons(IP_DF); 00183 nskb->nh.iph->id = 0; 00184 00185 /* Adjust IP checksum */ 00186 nskb->nh.iph->check = 0; 00187 nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph, 00188 nskb->nh.iph->ihl); 00189 00190 /* "Never happens" */ 00191 if (nskb->len > nskb->dst->pmtu) 00192 goto free_nskb; 00193 00194 connection_attach(nskb, oldskb->nfct); 00195 00196 NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, 00197 ip_finish_output); 00198 return; 00199 00200 free_nskb: 00201 kfree_skb(nskb); 00202 } 00203 00204 static void send_unreach(struct sk_buff *skb_in, int code) 00205 { 00206 struct iphdr *iph; 00207 struct udphdr *udph; 00208 struct icmphdr *icmph; 00209 struct sk_buff *nskb; 00210 u32 saddr; 00211 u8 tos; 00212 int hh_len, length; 00213 struct rtable *rt = (struct rtable*)skb_in->dst; 00214 unsigned char *data; 00215 00216 if (!rt) 00217 return; 00218 00219 /* FIXME: Use sysctl number. --RR */ 00220 if (!xrlim_allow(&rt->u.dst, 1*HZ)) 00221 return; 00222 00223 iph = skb_in->nh.iph; 00224 00225 /* No replies to physical multicast/broadcast */ 00226 if (skb_in->pkt_type!=PACKET_HOST) 00227 return; 00228 00229 /* Now check at the protocol level */ 00230 if (rt->rt_flags&(RTCF_BROADCAST|RTCF_MULTICAST)) 00231 return; 00232 00233 /* Only reply to fragment 0. */ 00234 if (iph->frag_off&htons(IP_OFFSET)) 00235 return; 00236 00237 /* if UDP checksum is set, verify it's correct */ 00238 if (iph->protocol == IPPROTO_UDP 00239 && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) { 00240 int datalen = skb_in->len - (iph->ihl<<2); 00241 udph = (struct udphdr *)((char *)iph + (iph->ihl<<2)); 00242 if (udph->check 00243 && csum_tcpudp_magic(iph->saddr, iph->daddr, 00244 datalen, IPPROTO_UDP, 00245 csum_partial((char *)udph, datalen, 00246 0)) != 0) 00247 return; 00248 } 00249 00250 /* If we send an ICMP error to an ICMP error a mess would result.. */ 00251 if (iph->protocol == IPPROTO_ICMP 00252 && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) { 00253 icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2)); 00254 /* Between echo-reply (0) and timestamp (13), 00255 everything except echo-request (8) is an error. 00256 Also, anything greater than NR_ICMP_TYPES is 00257 unknown, and hence should be treated as an error... */ 00258 if ((icmph->type < ICMP_TIMESTAMP 00259 && icmph->type != ICMP_ECHOREPLY 00260 && icmph->type != ICMP_ECHO) 00261 || icmph->type > NR_ICMP_TYPES) 00262 return; 00263 } 00264 00265 saddr = iph->daddr; 00266 if (!(rt->rt_flags & RTCF_LOCAL)) 00267 saddr = 0; 00268 00269 tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL; 00270 00271 if (ip_route_output(&rt, iph->saddr, saddr, RT_TOS(tos), 0)) 00272 return; 00273 00274 /* RFC says return as much as we can without exceeding 576 bytes. */ 00275 length = skb_in->len + sizeof(struct iphdr) + sizeof(struct icmphdr); 00276 00277 if (length > rt->u.dst.pmtu) 00278 length = rt->u.dst.pmtu; 00279 if (length > 576) 00280 length = 576; 00281 00282 hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15; 00283 00284 nskb = alloc_skb(hh_len+15+length, GFP_ATOMIC); 00285 if (!nskb) { 00286 ip_rt_put(rt); 00287 return; 00288 } 00289 00290 nskb->priority = 0; 00291 nskb->dst = &rt->u.dst; 00292 skb_reserve(nskb, hh_len); 00293 00294 /* Set up IP header */ 00295 iph = nskb->nh.iph 00296 = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); 00297 iph->version=4; 00298 iph->ihl=5; 00299 iph->tos=tos; 00300 iph->tot_len = htons(length); 00301 00302 /* PMTU discovery never applies to ICMP packets. */ 00303 iph->frag_off = 0; 00304 00305 iph->ttl = MAXTTL; 00306 ip_select_ident(iph, &rt->u.dst, NULL); 00307 iph->protocol=IPPROTO_ICMP; 00308 iph->saddr=rt->rt_src; 00309 iph->daddr=rt->rt_dst; 00310 iph->check=0; 00311 iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); 00312 00313 /* Set up ICMP header. */ 00314 icmph = nskb->h.icmph 00315 = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr)); 00316 icmph->type = ICMP_DEST_UNREACH; 00317 icmph->code = code; 00318 icmph->un.gateway = 0; 00319 icmph->checksum = 0; 00320 00321 /* Copy as much of original packet as will fit */ 00322 data = skb_put(nskb, 00323 length - sizeof(struct iphdr) - sizeof(struct icmphdr)); 00324 /* FIXME: won't work with nonlinear skbs --RR */ 00325 memcpy(data, skb_in->nh.iph, 00326 length - sizeof(struct iphdr) - sizeof(struct icmphdr)); 00327 icmph->checksum = ip_compute_csum((unsigned char *)icmph, 00328 length - sizeof(struct iphdr)); 00329 00330 connection_attach(nskb, skb_in->nfct); 00331 00332 NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev, 00333 ip_finish_output); 00334 } 00335 00336 static unsigned int reject(struct sk_buff **pskb, 00337 unsigned int hooknum, 00338 const struct net_device *in, 00339 const struct net_device *out, 00340 const void *targinfo, 00341 void *userinfo) 00342 { 00343 const struct ipt_reject_info *reject = targinfo; 00344 00345 /* Our naive response construction doesn't deal with IP 00346 options, and probably shouldn't try. */ 00347 if ((*pskb)->nh.iph->ihl<<2 != sizeof(struct iphdr)) 00348 return NF_DROP; 00349 00350 /* WARNING: This code causes reentry within iptables. 00351 This means that the iptables jump stack is now crap. We 00352 must return an absolute verdict. --RR */ 00353 switch (reject->with) { 00354 case IPT_ICMP_NET_UNREACHABLE: 00355 send_unreach(*pskb, ICMP_NET_UNREACH); 00356 break; 00357 case IPT_ICMP_HOST_UNREACHABLE: 00358 send_unreach(*pskb, ICMP_HOST_UNREACH); 00359 break; 00360 case IPT_ICMP_PROT_UNREACHABLE: 00361 send_unreach(*pskb, ICMP_PROT_UNREACH); 00362 break; 00363 case IPT_ICMP_PORT_UNREACHABLE: 00364 send_unreach(*pskb, ICMP_PORT_UNREACH); 00365 break; 00366 case IPT_ICMP_NET_PROHIBITED: 00367 send_unreach(*pskb, ICMP_NET_ANO); 00368 break; 00369 case IPT_ICMP_HOST_PROHIBITED: 00370 send_unreach(*pskb, ICMP_HOST_ANO); 00371 break; 00372 case IPT_ICMP_ADMIN_PROHIBITED: 00373 send_unreach(*pskb, ICMP_PKT_FILTERED); 00374 break; 00375 case IPT_TCP_RESET: 00376 send_reset(*pskb, hooknum); 00377 case IPT_ICMP_ECHOREPLY: 00378 /* Doesn't happen. */ 00379 break; 00380 } 00381 00382 return NF_DROP; 00383 } 00384 00385 static int check(const char *tablename, 00386 const struct ipt_entry *e, 00387 void *targinfo, 00388 unsigned int targinfosize, 00389 unsigned int hook_mask) 00390 { 00391 const struct ipt_reject_info *rejinfo = targinfo; 00392 00393 if (targinfosize != IPT_ALIGN(sizeof(struct ipt_reject_info))) { 00394 DEBUGP("REJECT: targinfosize %u != 0\n", targinfosize); 00395 return 0; 00396 } 00397 00398 /* Only allow these for packet filtering. */ 00399 if (strcmp(tablename, "filter") != 0) { 00400 DEBUGP("REJECT: bad table `%s'.\n", tablename); 00401 return 0; 00402 } 00403 if ((hook_mask & ~((1 << NF_IP_LOCAL_IN) 00404 | (1 << NF_IP_FORWARD) 00405 | (1 << NF_IP_LOCAL_OUT))) != 0) { 00406 DEBUGP("REJECT: bad hook mask %X\n", hook_mask); 00407 return 0; 00408 } 00409 00410 if (rejinfo->with == IPT_ICMP_ECHOREPLY) { 00411 printk("REJECT: ECHOREPLY no longer supported.\n"); 00412 return 0; 00413 } else if (rejinfo->with == IPT_TCP_RESET) { 00414 /* Must specify that it's a TCP packet */ 00415 if (e->ip.proto != IPPROTO_TCP 00416 || (e->ip.invflags & IPT_INV_PROTO)) { 00417 DEBUGP("REJECT: TCP_RESET illegal for non-tcp\n"); 00418 return 0; 00419 } 00420 } 00421 00422 return 1; 00423 } 00424 00425 static struct ipt_target ipt_reject_reg 00426 = { { NULL, NULL }, "REJECT", reject, check, NULL, THIS_MODULE }; 00427 00428 static int __init init(void) 00429 { 00430 if (ipt_register_target(&ipt_reject_reg)) 00431 return -EINVAL; 00432 return 0; 00433 } 00434 00435 static void __exit fini(void) 00436 { 00437 ipt_unregister_target(&ipt_reject_reg); 00438 } 00439 00440 module_init(init); 00441 module_exit(fini); 00442 MODULE_LICENSE("GPL");

Generated on Wed Dec 1 21:25:32 2004 for Linux 2.4.23 Networking by doxygen 1.3.8