I recommend using ip tables, but since you are also asking how to hack the kernel, here is an explanation of how you could do this (I use the 4.1.20 kernel as a reference):
When a packet is received (sk_buff), the IP protocol handler will send it to the registered network protocol:
static int ip_local_deliver_finish(struct sock *sk, struct sk_buff *skb) { ... ipprot = rcu_dereference(inet_protos[protocol]); if (ipprot) { ... ret = ipprot->handler(skb);
Assuming TCP protocol, handler: tcp_v4_rcv:
static const struct net_protocol tcp_protocol = { .early_demux = tcp_v4_early_demux, .handler = tcp_v4_rcv, .err_handler = tcp_v4_err, .no_policy = 1, .netns_ok = 1, .icmp_strict_tag_validation = 1, };
This is how tcp_v4_cv is called. It will try to find the socket for the resulting skb, and if not, it will send a reset:
int tcp_v4_rcv(struct sk_buff *skb) { sk = __inet_lookup_skb(&tcp_hashinfo, skb, th->source, th->dest); if (!sk) goto no_tcp_socket; no_tcp_socket: if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) goto discard_it; tcp_v4_send_reset(NULL, skb); ...
There are many different ways to hack this. You can go to the xfrm4_policy_check function and hack / modify the policy for AF_INET. Either you can simply comment on the line that calls xfrm4_policy_check, so the code will always go to discard_it, or you can just comment on the line that calls tcp_v4_send_reset (which will have more consequences, though).
Hope this helps.