OpenVPN
clinat.c
Go to the documentation of this file.
1/*
2 * OpenVPN -- An application to securely tunnel IP networks
3 * over a single TCP/UDP port, with support for SSL/TLS-based
4 * session authentication and key exchange,
5 * packet encryption, packet authentication, and
6 * packet compression.
7 *
8 * Copyright (C) 2002-2024 OpenVPN Inc <sales@openvpn.net>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 */
23
24#ifdef HAVE_CONFIG_H
25#include "config.h"
26#endif
27
28#include "syshead.h"
29
30#include "clinat.h"
31#include "proto.h"
32#include "socket.h"
33#include "memdbg.h"
34
35static bool
37 const struct client_nat_entry *e)
38{
39 if (dest->n >= MAX_CLIENT_NAT)
40 {
41 msg(M_WARN, "WARNING: client-nat table overflow (max %d entries)", MAX_CLIENT_NAT);
42 return false;
43 }
44 else
45 {
46 dest->entries[dest->n++] = *e;
47 return true;
48 }
49}
50
51void
52print_client_nat_list(const struct client_nat_option_list *list, int msglevel)
53{
54 struct gc_arena gc = gc_new();
55 int i;
56
57 msg(msglevel, "*** CNAT list");
58 if (list)
59 {
60 for (i = 0; i < list->n; ++i)
61 {
62 const struct client_nat_entry *e = &list->entries[i];
63 msg(msglevel, " CNAT[%d] t=%d %s/%s/%s",
64 i,
65 e->type,
69 }
70 }
71 gc_free(&gc);
72}
73
76{
77 struct client_nat_option_list *ret;
79 return ret;
80}
81
84{
85 struct client_nat_option_list *ret;
87 *ret = *src;
88 return ret;
89}
90
91void
93 const struct client_nat_option_list *src)
94{
95 int i;
96 for (i = 0; i < src->n; ++i)
97 {
98 if (!add_entry(dest, &src->entries[i]))
99 {
100 break;
101 }
102 }
103}
104
105void
107 const char *type,
108 const char *network,
109 const char *netmask,
110 const char *foreign_network,
111 int msglevel)
112{
113 struct client_nat_entry e;
114 bool ok;
115
116 if (!strcmp(type, "snat"))
117 {
118 e.type = CN_SNAT;
119 }
120 else if (!strcmp(type, "dnat"))
121 {
122 e.type = CN_DNAT;
123 }
124 else
125 {
126 msg(msglevel, "client-nat: type must be 'snat' or 'dnat'");
127 return;
128 }
129
130 e.network = getaddr(0, network, 0, &ok, NULL);
131 if (!ok)
132 {
133 msg(msglevel, "client-nat: bad network: %s", network);
134 return;
135 }
136 e.netmask = getaddr(0, netmask, 0, &ok, NULL);
137 if (!ok)
138 {
139 msg(msglevel, "client-nat: bad netmask: %s", netmask);
140 return;
141 }
142 e.foreign_network = getaddr(0, foreign_network, 0, &ok, NULL);
143 if (!ok)
144 {
145 msg(msglevel, "client-nat: bad foreign network: %s", foreign_network);
146 return;
147 }
148
149 add_entry(dest, &e);
150}
151
152#if 0
153static void
154print_checksum(struct openvpn_iphdr *iph, const char *prefix)
155{
156 uint16_t *sptr;
157 unsigned int sum = 0;
158 int i = 0;
159 for (sptr = (uint16_t *)iph; (uint8_t *)sptr < (uint8_t *)iph + sizeof(struct openvpn_iphdr); sptr++)
160 {
161 i += 1;
162 sum += *sptr;
163 }
164 msg(M_INFO, "** CKSUM[%d] %s %08x", i, prefix, sum);
165}
166#endif
167
168static void
169print_pkt(struct openvpn_iphdr *iph, const char *prefix, const int direction, const int msglevel)
170{
171 struct gc_arena gc = gc_new();
172
173 char *dirstr = "???";
174 if (direction == CN_OUTGOING)
175 {
176 dirstr = "OUT";
177 }
178 else if (direction == CN_INCOMING)
179 {
180 dirstr = "IN";
181 }
182
183 msg(msglevel, "** CNAT %s %s %s -> %s",
184 dirstr,
185 prefix,
188
189 gc_free(&gc);
190}
191
192void
194 struct buffer *ipbuf,
195 const int direction)
196{
197 struct ip_tcp_udp_hdr *h = (struct ip_tcp_udp_hdr *) BPTR(ipbuf);
198 int i;
199 uint32_t addr, *addr_ptr;
200 const uint32_t *from, *to;
201 int accumulate = 0;
202 unsigned int amask;
203 unsigned int alog = 0;
204
206 {
207 print_pkt(&h->ip, "BEFORE", direction, D_CLIENT_NAT);
208 }
209
210 for (i = 0; i < list->n; ++i)
211 {
212 const struct client_nat_entry *e = &list->entries[i]; /* current NAT rule */
213 if (e->type ^ direction)
214 {
215 addr = *(addr_ptr = &h->ip.daddr);
216 amask = 2;
217 }
218 else
219 {
220 addr = *(addr_ptr = &h->ip.saddr);
221 amask = 1;
222 }
223 if (direction)
224 {
225 from = &e->foreign_network;
226 to = &e->network;
227 }
228 else
229 {
230 from = &e->network;
231 to = &e->foreign_network;
232 }
233
234 if (((addr & e->netmask) == *from) && !(amask & alog))
235 {
236 /* pre-adjust IP checksum */
237 ADD_CHECKSUM_32(accumulate, addr);
238
239 /* do NAT transform */
240 addr = (addr & ~e->netmask) | *to;
241
242 /* post-adjust IP checksum */
243 SUB_CHECKSUM_32(accumulate, addr);
244
245 /* write the modified address to packet */
246 *addr_ptr = addr;
247
248 /* mark as modified */
249 alog |= amask;
250 }
251 }
252 if (alog)
253 {
255 {
256 print_pkt(&h->ip, "AFTER", direction, D_CLIENT_NAT);
257 }
258
259 ADJUST_CHECKSUM(accumulate, h->ip.check);
260
262 {
263 if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_tcphdr))
264 {
265 ADJUST_CHECKSUM(accumulate, h->u.tcp.check);
266 }
267 }
268 else if (h->ip.protocol == OPENVPN_IPPROTO_UDP)
269 {
270 if (BLEN(ipbuf) >= sizeof(struct openvpn_iphdr) + sizeof(struct openvpn_udphdr))
271 {
272 ADJUST_CHECKSUM(accumulate, h->u.udp.check);
273 }
274 }
275 }
276}
#define BPTR(buf)
Definition buffer.h:124
#define ALLOC_OBJ_CLEAR_GC(dptr, type, gc)
Definition buffer.h:1097
#define BLEN(buf)
Definition buffer.h:127
#define ALLOC_OBJ_GC(dptr, type, gc)
Definition buffer.h:1092
static void gc_free(struct gc_arena *a)
Definition buffer.h:1033
static struct gc_arena gc_new(void)
Definition buffer.h:1025
void print_client_nat_list(const struct client_nat_option_list *list, int msglevel)
Definition clinat.c:52
void client_nat_transform(const struct client_nat_option_list *list, struct buffer *ipbuf, const int direction)
Definition clinat.c:193
static void print_pkt(struct openvpn_iphdr *iph, const char *prefix, const int direction, const int msglevel)
Definition clinat.c:169
static bool add_entry(struct client_nat_option_list *dest, const struct client_nat_entry *e)
Definition clinat.c:36
void add_client_nat_to_option_list(struct client_nat_option_list *dest, const char *type, const char *network, const char *netmask, const char *foreign_network, int msglevel)
Definition clinat.c:106
struct client_nat_option_list * new_client_nat_list(struct gc_arena *gc)
Definition clinat.c:75
struct client_nat_option_list * clone_client_nat_option_list(const struct client_nat_option_list *src, struct gc_arena *gc)
Definition clinat.c:83
void copy_client_nat_option_list(struct client_nat_option_list *dest, const struct client_nat_option_list *src)
Definition clinat.c:92
#define CN_INCOMING
Definition clinat.h:32
#define CN_SNAT
Definition clinat.h:35
#define MAX_CLIENT_NAT
Definition clinat.h:29
#define CN_OUTGOING
Definition clinat.h:31
#define CN_DNAT
Definition clinat.h:36
#define M_INFO
Definition errlevel.h:55
#define D_CLIENT_NAT
Definition errlevel.h:116
static bool check_debug_level(unsigned int level)
Definition error.h:220
#define msg(flags,...)
Definition error.h:144
#define M_WARN
Definition error.h:91
#define SUB_CHECKSUM_32(acc, u32)
Definition proto.h:231
#define ADJUST_CHECKSUM(acc, cksum)
Definition proto.h:211
#define OPENVPN_IPPROTO_UDP
Definition proto.h:108
#define OPENVPN_IPPROTO_TCP
Definition proto.h:107
#define ADD_CHECKSUM_32(acc, u32)
Definition proto.h:226
const char * print_in_addr_t(in_addr_t addr, unsigned int flags, struct gc_arena *gc)
Definition socket.c:2974
in_addr_t getaddr(unsigned int flags, const char *hostname, int resolve_retry_seconds, bool *succeeded, struct signal_info *sig_info)
Translate an IPv4 addr or hostname from string form to in_addr_t.
Definition socket.c:195
#define IA_NET_ORDER
Definition socket.h:402
Wrapper structure for dynamically allocated memory.
Definition buffer.h:61
Definition clinat.h:34
int type
Definition clinat.h:37
in_addr_t network
Definition clinat.h:38
in_addr_t foreign_network
Definition clinat.h:40
in_addr_t netmask
Definition clinat.h:39
struct client_nat_entry entries[MAX_CLIENT_NAT]
Definition clinat.h:45
Garbage collection arena used to keep track of dynamically allocated memory.
Definition buffer.h:117
struct gc_entry * list
First element of the linked list of gc_entry structures.
Definition buffer.h:118
union ip_tcp_udp_hdr::@18 u
struct openvpn_iphdr ip
Definition proto.h:194
struct openvpn_udphdr udp
Definition proto.h:197
struct openvpn_tcphdr tcp
Definition proto.h:196
uint32_t saddr
Definition proto.h:113
uint32_t daddr
Definition proto.h:114
uint8_t protocol
Definition proto.h:110
uint16_t check
Definition proto.h:112
uint16_t check
Definition proto.h:184
uint16_t check
Definition proto.h:158
struct gc_arena gc
Definition test_ssl.c:155