summaryrefslogtreecommitdiff
path: root/target/linux/generic-2.4/patches/109-ipsec_nat_traversal.patch
blob: 51981b8afc5e140a8ff78dc3025a1f2ef834be79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
packaging/utils/nattpatch 2.4
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -488,7 +488,13 @@ struct tcp_opt {
 	} bictcp;
 };
 
- 	
+#if 1
+#define UDP_OPT_IN_SOCK 1
+struct udp_opt {
+	__u32 esp_in_udp;
+};
+#endif
+
 /*
  * This structure really needs to be cleaned up.
  * Most of it is for TCP, and not used by any of
@@ -655,6 +661,9 @@ struct sock {
 #if defined(CONFIG_SPX) || defined (CONFIG_SPX_MODULE)
 		struct spx_opt		af_spx;
 #endif /* CONFIG_SPX */
+#if 1
+		struct udp_opt          af_udp;
+#endif
 
 	} tp_pinfo;
 
--- a/net/Config.in
+++ b/net/Config.in
@@ -104,4 +104,6 @@ comment 'Network testing'
 dep_tristate 'Packet Generator (USE WITH CAUTION)' CONFIG_NET_PKTGEN $CONFIG_PROC_FS
 endmenu
 
+bool 'IPSEC NAT-Traversal' CONFIG_IPSEC_NAT_TRAVERSAL
+
 endmenu
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -860,6 +860,9 @@ static void udp_close(struct sock *sk, l
 
 static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
 {
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	struct udp_opt *tp =  &(sk->tp_pinfo.af_udp);
+#endif
 	/*
 	 *	Charge it to the socket, dropping if the queue is full.
 	 */
@@ -877,6 +880,40 @@ static int udp_queue_rcv_skb(struct sock
 	}
 #endif
 
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+	if (tp->esp_in_udp) {
+		/*
+		 * Set skb->sk and xmit packet to ipsec_rcv.
+		 *
+		 * If ret != 0, ipsec_rcv refused the packet (not ESPinUDP),
+		 * restore skb->sk and fall back to sock_queue_rcv_skb
+		 */
+		struct inet_protocol *esp = NULL;
+
+#if defined(CONFIG_KLIPS) && !defined(CONFIG_KLIPS_MODULE)
+               /* optomize only when we know it is statically linked */
+		extern struct inet_protocol esp_protocol;
+		esp = &esp_protocol;
+#else
+		for (esp = (struct inet_protocol *)inet_protos[IPPROTO_ESP & (MAX_INET_PROTOS - 1)];
+			(esp) && (esp->protocol != IPPROTO_ESP);
+			esp = esp->next);
+#endif
+
+		if (esp && esp->handler) {
+			struct sock *sav_sk = skb->sk;
+			skb->sk = sk;
+			if (esp->handler(skb) == 0) {
+				skb->sk = sav_sk;
+				/*not sure we might count ESPinUDP as UDP...*/
+				UDP_INC_STATS_BH(UdpInDatagrams);
+				return 0;
+			}
+			skb->sk = sav_sk;
+		}
+	}
+#endif
+
 	if (sock_queue_rcv_skb(sk,skb)<0) {
 		UDP_INC_STATS_BH(UdpInErrors);
 		IP_INC_STATS_BH(IpInDiscards);
@@ -1100,13 +1137,49 @@ out:
 	return len;
 }
 
+static int udp_setsockopt(struct sock *sk, int level, int optname,
+	char *optval, int optlen)
+{
+	struct udp_opt *tp = &(sk->tp_pinfo.af_udp);
+	int val;
+	int err = 0;
+
+	if (level != SOL_UDP)
+		return ip_setsockopt(sk, level, optname, optval, optlen);
+
+	if(optlen<sizeof(int))
+		return -EINVAL;
+
+	if (get_user(val, (int *)optval))
+		return -EFAULT;
+	
+	lock_sock(sk);
+
+	switch(optname) {
+#ifdef CONFIG_IPSEC_NAT_TRAVERSAL
+#ifndef UDP_ESPINUDP
+#define UDP_ESPINUDP 100
+#endif
+		case UDP_ESPINUDP:
+			tp->esp_in_udp = val;
+			break;
+#endif
+		default:
+			err = -ENOPROTOOPT;
+			break;
+	}
+
+	release_sock(sk);
+	return err;
+}
+
 struct proto udp_prot = {
  	name:		"UDP",
 	close:		udp_close,
 	connect:	udp_connect,
 	disconnect:	udp_disconnect,
 	ioctl:		udp_ioctl,
-	setsockopt:	ip_setsockopt,
+	setsockopt:	udp_setsockopt,
 	getsockopt:	ip_getsockopt,
 	sendmsg:	udp_sendmsg,
 	recvmsg:	udp_recvmsg,