1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Generic address resultion entity 4 * 5 * Authors: 6 * net_random Alan Cox 7 * net_ratelimit Andi Kleen 8 * in{4,6}_pton YOSHIFUJI Hideaki, Copyright (C)2006 USAGI/WIDE Project 9 * 10 * Created by Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 11 */ 12 13 #include <linux/module.h> 14 #include <linux/jiffies.h> 15 #include <linux/kernel.h> 16 #include <linux/ctype.h> 17 #include <linux/inet.h> 18 #include <linux/mm.h> 19 #include <linux/net.h> 20 #include <linux/string.h> 21 #include <linux/types.h> 22 #include <linux/percpu.h> 23 #include <linux/init.h> 24 #include <linux/ratelimit.h> 25 #include <linux/socket.h> 26 27 #include <net/sock.h> 28 #include <net/net_ratelimit.h> 29 #include <net/ipv6.h> 30 31 #include <asm/byteorder.h> 32 #include <linux/uaccess.h> 33 34 DEFINE_RATELIMIT_STATE(net_ratelimit_state, 5 * HZ, 10); 35 /* 36 * All net warning printk()s should be guarded by this function. 37 */ 38 int net_ratelimit(void) 39 { 40 return __ratelimit(&net_ratelimit_state); 41 } 42 EXPORT_SYMBOL(net_ratelimit); 43 44 /* 45 * Convert an ASCII string to binary IP. 46 * This is outside of net/ipv4/ because various code that uses IP addresses 47 * is otherwise not dependent on the TCP/IP stack. 48 */ 49 50 __be32 in_aton(const char *str) 51 { 52 unsigned int l; 53 unsigned int val; 54 int i; 55 56 l = 0; 57 for (i = 0; i < 4; i++) { 58 l <<= 8; 59 if (*str != '\0') { 60 val = 0; 61 while (*str != '\0' && *str != '.' && *str != '\n') { 62 val *= 10; 63 val += *str - ''; 64 str++; 65 } 66 l |= val; 67 if (*str != '\0') 68 str++; 69 } 70 } 71 return htonl(l); 72 } 73 EXPORT_SYMBOL(in_aton); 74 75 #define IN6PTON_XDIGIT 0x00010000 76 #define IN6PTON_DIGIT 0x00020000 77 #define IN6PTON_COLON_MASK 0x00700000 78 #define IN6PTON_COLON_1 0x00100000 /* single : requested */ 79 #define IN6PTON_COLON_2 0x00200000 /* second : requested */ 80 #define IN6PTON_COLON_1_2 0x00400000 /* :: requested */ 81 #define IN6PTON_DOT 0x00800000 /* . */ 82 #define IN6PTON_DELIM 0x10000000 83 #define IN6PTON_NULL 0x20000000 /* first/tail */ 84 #define IN6PTON_UNKNOWN 0x40000000 85 86 static inline int xdigit2bin(char c, int delim) 87 { 88 int val; 89 90 if (c == delim || c == '\0') 91 return IN6PTON_DELIM; 92 if (c == ':') 93 return IN6PTON_COLON_MASK; 94 if (c == '.') 95 return IN6PTON_DOT; 96 97 val = hex_to_bin(c); 98 if (val >= 0) 99 return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0); 100 101 if (delim == -1) 102 return IN6PTON_DELIM; 103 return IN6PTON_UNKNOWN; 104 } 105 106 /** 107 * in4_pton - convert an IPv4 address from literal to binary representation 108 * @src: the start of the IPv4 address string 109 * @srclen: the length of the string, -1 means strlen(src) 110 * @dst: the binary (u8[4] array) representation of the IPv4 address 111 * @delim: the delimiter of the IPv4 address in @src, -1 means no delimiter 112 * @end: A pointer to the end of the parsed string will be placed here 113 * 114 * Return one on success, return zero when any error occurs 115 * and @end will point to the end of the parsed string. 116 * 117 */ 118 int in4_pton(const char *src, int srclen, 119 u8 *dst, 120 int delim, const char **end) 121 { 122 const char *s; 123 u8 *d; 124 u8 dbuf[4]; 125 int ret = 0; 126 int i; 127 int w = 0; 128 129 if (srclen < 0) 130 srclen = strlen(src); 131 s = src; 132 d = dbuf; 133 i = 0; 134 while (1) { 135 int c; 136 c = xdigit2bin(srclen > 0 ? *s : '\0', delim); 137 if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) { 138 goto out; 139 } 140 if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) { 141 if (w == 0) 142 goto out; 143 *d++ = w & 0xff; 144 w = 0; 145 i++; 146 if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { 147 if (i != 4) 148 goto out; 149 break; 150 } 151 goto cont; 152 } 153 w = (w * 10) + c; 154 if ((w & 0xffff) > 255) { 155 goto out; 156 } 157 cont: 158 if (i >= 4) 159 goto out; 160 s++; 161 srclen--; 162 } 163 ret = 1; 164 memcpy(dst, dbuf, sizeof(dbuf)); 165 out: 166 if (end) 167 *end = s; 168 return ret; 169 } 170 EXPORT_SYMBOL(in4_pton); 171 172 /** 173 * in6_pton - convert an IPv6 address from literal to binary representation 174 * @src: the start of the IPv6 address string 175 * @srclen: the length of the string, -1 means strlen(src) 176 * @dst: the binary (u8[16] array) representation of the IPv6 address 177 * @delim: the delimiter of the IPv6 address in @src, -1 means no delimiter 178 * @end: A pointer to the end of the parsed string will be placed here 179 * 180 * Return one on success, return zero when any error occurs 181 * and @end will point to the end of the parsed string. 182 * 183 */ 184 int in6_pton(const char *src, int srclen, 185 u8 *dst, 186 int delim, const char **end) 187 { 188 const char *s, *tok = NULL; 189 u8 *d, *dc = NULL; 190 u8 dbuf[16]; 191 int ret = 0; 192 int i; 193 int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL; 194 int w = 0; 195 196 memset(dbuf, 0, sizeof(dbuf)); 197 198 s = src; 199 d = dbuf; 200 if (srclen < 0) 201 srclen = strlen(src); 202 203 while (1) { 204 int c; 205 206 c = xdigit2bin(srclen > 0 ? *s : '\0', delim); 207 if (!(c & state)) 208 goto out; 209 if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) { 210 /* process one 16-bit word */ 211 if (!(state & IN6PTON_NULL)) { 212 *d++ = (w >> 8) & 0xff; 213 *d++ = w & 0xff; 214 } 215 w = 0; 216 if (c & IN6PTON_DELIM) { 217 /* We've processed last word */ 218 break; 219 } 220 /* 221 * COLON_1 => XDIGIT 222 * COLON_2 => XDIGIT|DELIM 223 * COLON_1_2 => COLON_2 224 */ 225 switch (state & IN6PTON_COLON_MASK) { 226 case IN6PTON_COLON_2: 227 dc = d; 228 state = IN6PTON_XDIGIT | IN6PTON_DELIM; 229 if (dc - dbuf >= sizeof(dbuf)) 230 state |= IN6PTON_NULL; 231 break; 232 case IN6PTON_COLON_1|IN6PTON_COLON_1_2: 233 state = IN6PTON_XDIGIT | IN6PTON_COLON_2; 234 break; 235 case IN6PTON_COLON_1: 236 state = IN6PTON_XDIGIT; 237 break; 238 case IN6PTON_COLON_1_2: 239 state = IN6PTON_COLON_2; 240 break; 241 default: 242 state = 0; 243 } 244 tok = s + 1; 245 goto cont; 246 } 247 248 if (c & IN6PTON_DOT) { 249 ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s); 250 if (ret > 0) { 251 d += 4; 252 break; 253 } 254 goto out; 255 } 256 257 w = (w << 4) | (0xff & c); 258 state = IN6PTON_COLON_1 | IN6PTON_DELIM; 259 if (!(w & 0xf000)) { 260 state |= IN6PTON_XDIGIT; 261 } 262 if (!dc && d + 2 < dbuf + sizeof(dbuf)) { 263 state |= IN6PTON_COLON_1_2; 264 state &= ~IN6PTON_DELIM; 265 } 266 if (d + 2 >= dbuf + sizeof(dbuf)) { 267 state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2); 268 } 269 cont: 270 if ((dc && d + 4 < dbuf + sizeof(dbuf)) || 271 d + 4 == dbuf + sizeof(dbuf)) { 272 state |= IN6PTON_DOT; 273 } 274 if (d >= dbuf + sizeof(dbuf)) { 275 state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK); 276 } 277 s++; 278 srclen--; 279 } 280 281 i = 15; d--; 282 283 if (dc) { 284 while (d >= dc) 285 dst[i--] = *d--; 286 while (i >= dc - dbuf) 287 dst[i--] = 0; 288 while (i >= 0) 289 dst[i--] = *d--; 290 } else 291 memcpy(dst, dbuf, sizeof(dbuf)); 292 293 ret = 1; 294 out: 295 if (end) 296 *end = s; 297 return ret; 298 } 299 EXPORT_SYMBOL(in6_pton); 300 301 static int inet4_pton(const char *src, u16 port_num, 302 struct sockaddr_storage *addr) 303 { 304 struct sockaddr_in *addr4 = (struct sockaddr_in *)addr; 305 size_t srclen = strlen(src); 306 307 if (srclen > INET_ADDRSTRLEN) 308 return -EINVAL; 309 310 if (in4_pton(src, srclen, (u8 *)&addr4->sin_addr.s_addr, 311 '\n', NULL) == 0) 312 return -EINVAL; 313 314 addr4->sin_family = AF_INET; 315 addr4->sin_port = htons(port_num); 316 317 return 0; 318 } 319 320 static int inet6_pton(struct net *net, const char *src, u16 port_num, 321 struct sockaddr_storage *addr) 322 { 323 struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)addr; 324 const char *scope_delim; 325 size_t srclen = strlen(src); 326 327 if (srclen > INET6_ADDRSTRLEN) 328 return -EINVAL; 329 330 if (in6_pton(src, srclen, (u8 *)&addr6->sin6_addr.s6_addr, 331 '%', &scope_delim) == 0) 332 return -EINVAL; 333 334 if (ipv6_addr_type(&addr6->sin6_addr) & IPV6_ADDR_LINKLOCAL && 335 src + srclen != scope_delim && *scope_delim == '%') { 336 struct net_device *dev; 337 char scope_id[16]; 338 size_t scope_len = min_t(size_t, sizeof(scope_id) - 1, 339 src + srclen - scope_delim - 1); 340 341 memcpy(scope_id, scope_delim + 1, scope_len); 342 scope_id[scope_len] = '\0'; 343 344 dev = dev_get_by_name(net, scope_id); 345 if (dev) { 346 addr6->sin6_scope_id = dev->ifindex; 347 dev_put(dev); 348 } else if (kstrtouint(scope_id, 0, &addr6->sin6_scope_id)) { 349 return -EINVAL; 350 } 351 } 352 353 addr6->sin6_family = AF_INET6; 354 addr6->sin6_port = htons(port_num); 355 356 return 0; 357 } 358 359 /** 360 * inet_pton_with_scope - convert an IPv4/IPv6 and port to socket address 361 * @net: net namespace (used for scope handling) 362 * @af: address family, AF_INET, AF_INET6 or AF_UNSPEC for either 363 * @src: the start of the address string 364 * @port: the start of the port string (or NULL for none) 365 * @addr: output socket address 366 * 367 * Return zero on success, return errno when any error occurs. 368 */ 369 int inet_pton_with_scope(struct net *net, __kernel_sa_family_t af, 370 const char *src, const char *port, struct sockaddr_storage *addr) 371 { 372 u16 port_num; 373 int ret = -EINVAL; 374 375 if (port) { 376 if (kstrtou16(port, 0, &port_num)) 377 return -EINVAL; 378 } else { 379 port_num = 0; 380 } 381 382 switch (af) { 383 case AF_INET: 384 ret = inet4_pton(src, port_num, addr); 385 break; 386 case AF_INET6: 387 ret = inet6_pton(net, src, port_num, addr); 388 break; 389 case AF_UNSPEC: 390 ret = inet4_pton(src, port_num, addr); 391 if (ret) 392 ret = inet6_pton(net, src, port_num, addr); 393 break; 394 default: 395 pr_err("unexpected address family %d\n", af); 396 } 397 398 return ret; 399 } 400 EXPORT_SYMBOL(inet_pton_with_scope); 401 402 bool inet_addr_is_any(struct sockaddr *addr) 403 { 404 if (addr->sa_family == AF_INET6) { 405 struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)addr; 406 const struct sockaddr_in6 in6_any = 407 { .sin6_addr = IN6ADDR_ANY_INIT }; 408 409 if (!memcmp(in6->sin6_addr.s6_addr, 410 in6_any.sin6_addr.s6_addr, 16)) 411 return true; 412 } else if (addr->sa_family == AF_INET) { 413 struct sockaddr_in *in = (struct sockaddr_in *)addr; 414 415 if (in->sin_addr.s_addr == htonl(INADDR_ANY)) 416 return true; 417 } else { 418 pr_warn("unexpected address family %u\n", addr->sa_family); 419 } 420 421 return false; 422 } 423 EXPORT_SYMBOL(inet_addr_is_any); 424 425 void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb, 426 __be32 from, __be32 to, bool pseudohdr) 427 { 428 if (skb->ip_summed != CHECKSUM_PARTIAL) { 429 csum_replace4(sum, from, to); 430 if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) 431 skb->csum = ~csum_add(csum_sub(~(skb->csum), 432 (__force __wsum)from), 433 (__force __wsum)to); 434 } else if (pseudohdr) 435 *sum = ~csum_fold(csum_add(csum_sub(csum_unfold(*sum), 436 (__force __wsum)from), 437 (__force __wsum)to)); 438 } 439 EXPORT_SYMBOL(inet_proto_csum_replace4); 440 441 /** 442 * inet_proto_csum_replace16 - update layer 4 header checksum field 443 * @sum: Layer 4 header checksum field 444 * @skb: sk_buff for the packet 445 * @from: old IPv6 address 446 * @to: new IPv6 address 447 * @pseudohdr: True if layer 4 header checksum includes pseudoheader 448 * 449 * Update layer 4 header as per the update in IPv6 src/dst address. 450 * 451 * There is no need to update skb->csum in this function, because update in two 452 * fields a.) IPv6 src/dst address and b.) L4 header checksum cancels each other 453 * for skb->csum calculation. Whereas inet_proto_csum_replace4 function needs to 454 * update skb->csum, because update in 3 fields a.) IPv4 src/dst address, 455 * b.) IPv4 Header checksum and c.) L4 header checksum results in same diff as 456 * L4 Header checksum for skb->csum calculation. 457 */ 458 void inet_proto_csum_replace16(__sum16 *sum, struct sk_buff *skb, 459 const __be32 *from, const __be32 *to, 460 bool pseudohdr) 461 { 462 __be32 diff[] = { 463 ~from[0], ~from[1], ~from[2], ~from[3], 464 to[0], to[1], to[2], to[3], 465 }; 466 if (skb->ip_summed != CHECKSUM_PARTIAL) { 467 *sum = csum_fold(csum_partial(diff, sizeof(diff), 468 ~csum_unfold(*sum))); 469 } else if (pseudohdr) 470 *sum = ~csum_fold(csum_partial(diff, sizeof(diff), 471 csum_unfold(*sum))); 472 } 473 EXPORT_SYMBOL(inet_proto_csum_replace16); 474 475 void inet_proto_csum_replace_by_diff(__sum16 *sum, struct sk_buff *skb, 476 __wsum diff, bool pseudohdr) 477 { 478 if (skb->ip_summed != CHECKSUM_PARTIAL) { 479 csum_replace_by_diff(sum, diff); 480 if (skb->ip_summed == CHECKSUM_COMPLETE && pseudohdr) 481 skb->csum = ~csum_sub(diff, skb->csum); 482 } else if (pseudohdr) { 483 *sum = ~csum_fold(csum_add(diff, csum_unfold(*sum))); 484 } 485 } 486 EXPORT_SYMBOL(inet_proto_csum_replace_by_diff); 487
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.