|
| 1 | +// Copyright 2010 Garret Kelly. All Rights Reserved. |
| 2 | +// Author: [email protected] (Garret Kelly) |
| 3 | + |
| 4 | +#include <linux/module.h> |
| 5 | + |
| 6 | +#include <linux/tcp.h> |
| 7 | +#include <linux/ip.h> |
| 8 | +#include <linux/netfilter.h> |
| 9 | +#include <linux/netfilter_ipv4.h> |
| 10 | +#include <linux/skbuff.h> |
| 11 | + |
| 12 | +MODULE_AUTHOR("Garret Kelly"); |
| 13 | +MODULE_LICENSE("GPL v2"); |
| 14 | +MODULE_DESCRIPTION("A tiny port-knocking implementation that guards a single " |
| 15 | + "port from access with a user-specified knocking sequence"); |
| 16 | +MODULE_PARM_DESC(upk_protected_port, "The port to which access will be denied " |
| 17 | + "until the correct knocking sequence is recieved"); |
| 18 | +MODULE_PARM_DESC(upk_timeout, "The timeout, in jiffies, before the entered " |
| 19 | + "sequence resets itself if it has not been completed"); |
| 20 | +MODULE_PARM_DESC(upk_sequence, "The sequence of ports that must be 'knocked' " |
| 21 | + "upon for the protected port to be made accessbile"); |
| 22 | + |
| 23 | +#define UPK_MAX_SEQUENCE_LENGTH 10 |
| 24 | +#define UPK_INFO KERN_INFO "upk: " |
| 25 | + |
| 26 | +static int upk_protected_port = 22; |
| 27 | +static int upk_timeout = 5 * HZ; |
| 28 | +static int upk_sequence[UPK_MAX_SEQUENCE_LENGTH] = {1234, 4321, 4444, 0}; |
| 29 | +static int upk_sequence_length = UPK_MAX_SEQUENCE_LENGTH; |
| 30 | + |
| 31 | +module_param(upk_protected_port, int, 0); |
| 32 | +module_param(upk_timeout, int, 0); |
| 33 | +module_param_array(upk_sequence, int, &upk_sequence_length, 0); |
| 34 | + |
| 35 | +static int upk_open = false; |
| 36 | +static int upk_sequence_index = 0; |
| 37 | +static unsigned long upk_sequence_timestamp = 0; |
| 38 | +static struct nf_hook_ops upk_netfilter_hook; |
| 39 | + |
| 40 | +static void upk_reset(void) |
| 41 | +{ |
| 42 | + upk_open = false; |
| 43 | + upk_sequence_index = 0; |
| 44 | + upk_sequence_timestamp = 0; |
| 45 | +} |
| 46 | + |
| 47 | +static unsigned int upk_filter_function(unsigned int hooknum, |
| 48 | + struct sk_buff *skb, const struct net_device *in, |
| 49 | + const struct net_device *out, int (*okfn)(struct sk_buff *)) |
| 50 | +{ |
| 51 | + struct iphdr *ip_header; |
| 52 | + struct tcphdr *tcp_header; |
| 53 | + |
| 54 | + ip_header = ip_hdr(skb); |
| 55 | + if (!ip_header || ip_header->protocol != IPPROTO_TCP) { |
| 56 | + return NF_ACCEPT; |
| 57 | + } |
| 58 | + |
| 59 | + tcp_header = (struct tcphdr *)(skb->data + (ip_header->ihl * 4)); |
| 60 | + if (tcp_header->dest == htons(upk_protected_port)) { |
| 61 | + if (upk_open) { |
| 62 | + return NF_ACCEPT; |
| 63 | + } |
| 64 | + return NF_DROP; |
| 65 | + } else { |
| 66 | + if ((jiffies - upk_sequence_timestamp) > upk_timeout) { |
| 67 | + upk_reset(); |
| 68 | + } |
| 69 | + if (tcp_header->dest == htons(upk_sequence[upk_sequence_index])) { |
| 70 | + upk_sequence_timestamp = jiffies; |
| 71 | + upk_sequence_index++; |
| 72 | + if (upk_sequence[upk_sequence_index] == 0) { |
| 73 | + upk_open = true; |
| 74 | + } |
| 75 | + } |
| 76 | + } |
| 77 | + |
| 78 | + return NF_ACCEPT; |
| 79 | +} |
| 80 | + |
| 81 | +static int __init upk_init(void) |
| 82 | +{ |
| 83 | + upk_reset(); |
| 84 | + upk_sequence[upk_sequence_length] = 0; |
| 85 | + |
| 86 | + upk_netfilter_hook.hook = upk_filter_function; |
| 87 | + upk_netfilter_hook.hooknum = NF_INET_PRE_ROUTING; |
| 88 | + upk_netfilter_hook.pf = PF_INET; |
| 89 | + upk_netfilter_hook.priority = NF_IP_PRI_FIRST; |
| 90 | + nf_register_hook(&upk_netfilter_hook); |
| 91 | + |
| 92 | + printk(UPK_INFO "loaded\n"); |
| 93 | + |
| 94 | + return 0; |
| 95 | +} |
| 96 | + |
| 97 | +static void __exit upk_exit(void) |
| 98 | +{ |
| 99 | + nf_unregister_hook(&upk_netfilter_hook); |
| 100 | + |
| 101 | + printk(UPK_INFO "unloaded\n"); |
| 102 | +} |
| 103 | + |
| 104 | +module_init(upk_init); |
| 105 | +module_exit(upk_exit); |
0 commit comments