| 1 | /* |
| 2 | * Utility used to calculate the 6rd subnet. |
| 3 | * |
| 4 | * Copyright 2012, Stéphan Kochen <stephan@kochen.nl> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or |
| 7 | * modify it under the terms of the GNU General Public License |
| 8 | * as published by the Free Software Foundation; either version 2 |
| 9 | * of the License, or (at your option) any later version. |
| 10 | * |
| 11 | * This program is distributed in the hope that it will be useful, |
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 | * GNU General Public License for more details. |
| 15 | * |
| 16 | * You should have received a copy of the GNU General Public License |
| 17 | * along with this program; if not, write to the Free Software |
| 18 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
| 19 | */ |
| 20 | |
| 21 | #include <stdio.h> |
| 22 | #include <stdlib.h> |
| 23 | #include <string.h> |
| 24 | #include <sys/errno.h> |
| 25 | #include <arpa/inet.h> |
| 26 | #include <netinet/in.h> |
| 27 | |
| 28 | #define INET_PREFIXSTRLEN (INET_ADDRSTRLEN+3) |
| 29 | #define INET6_PREFIXSTRLEN (INET6_ADDRSTRLEN+4) |
| 30 | |
| 31 | static void print_usage() |
| 32 | { |
| 33 | fprintf(stderr, "Usage: 6rdcalc <v6 prefix>/<mask> <v4 address>/<mask>\n"); |
| 34 | exit(1); |
| 35 | } |
| 36 | |
| 37 | static void print_error() |
| 38 | { |
| 39 | fprintf(stderr, "%s", strerror(errno)); |
| 40 | exit(1); |
| 41 | } |
| 42 | |
| 43 | static void parse_str(int af, char *str, void *addr, unsigned long *mask) |
| 44 | { |
| 45 | int ret; |
| 46 | char *slash; |
| 47 | |
| 48 | /* Split the address at the slash. */ |
| 49 | if ((slash = strchr(str, '/')) == NULL) |
| 50 | print_usage(); |
| 51 | *slash = '\0'; |
| 52 | |
| 53 | /* Parse the address. */ |
| 54 | if ((ret = inet_pton(af, str, addr)) != 1) { |
| 55 | if (ret == 0) |
| 56 | print_usage(); |
| 57 | else |
| 58 | print_error(); |
| 59 | } |
| 60 | |
| 61 | /* Parse the mask. */ |
| 62 | *mask = strtoul(slash+1, NULL, 10); |
| 63 | if ((af == AF_INET && *mask > 32) || |
| 64 | (af == AF_INET6 && *mask > 128)) |
| 65 | print_usage(); |
| 66 | } |
| 67 | |
| 68 | int main(int argc, const char **argv) |
| 69 | { |
| 70 | char v6str[INET6_PREFIXSTRLEN], v4str[INET_PREFIXSTRLEN]; |
| 71 | struct in6_addr v6; |
| 72 | struct in_addr v4; |
| 73 | unsigned long v6it, v4it, mask; |
| 74 | unsigned char *byte4, *byte6; |
| 75 | unsigned char bit4, bit6; |
| 76 | |
| 77 | /* Check parameters. */ |
| 78 | if (argc != 3) |
| 79 | print_usage(); |
| 80 | |
| 81 | /* Parse the v6 address. */ |
| 82 | strncpy(v6str, argv[1], INET6_PREFIXSTRLEN); |
| 83 | v6str[INET6_PREFIXSTRLEN-1] = '\0'; |
| 84 | parse_str(AF_INET6, v6str, &v6, &v6it); |
| 85 | |
| 86 | /* Parse the v4 address */ |
| 87 | strncpy(v4str, argv[2], INET_PREFIXSTRLEN); |
| 88 | v6str[INET_PREFIXSTRLEN-1] = '\0'; |
| 89 | parse_str(AF_INET, v4str, &v4, &v4it); |
| 90 | |
| 91 | /* Check if the combined mask is within bounds. */ |
| 92 | mask = (32 - v4it) + v6it; |
| 93 | if (mask > 128) |
| 94 | print_usage(); |
| 95 | |
| 96 | /* Combine the addresses. */ |
| 97 | while (v4it < 32) { |
| 98 | byte6 = (unsigned char *)(&v6.s6_addr) + (v6it >> 3); |
| 99 | byte4 = (unsigned char *)(&v4.s_addr) + (v4it >> 3); |
| 100 | bit6 = 128 >> (v6it & 0x07); |
| 101 | bit4 = 128 >> (v4it & 0x07); |
| 102 | |
| 103 | if (*byte4 & bit4) |
| 104 | *byte6 |= bit6; |
| 105 | else |
| 106 | *byte6 &= ~bit6; |
| 107 | |
| 108 | v4it++; v6it++; |
| 109 | } |
| 110 | |
| 111 | /* Clear remaining bits. */ |
| 112 | while (v6it < 128) { |
| 113 | byte6 = (unsigned char *)(&v6.s6_addr) + (v6it >> 2); |
| 114 | bit6 = 128 >> (v6it & 0x07); |
| 115 | |
| 116 | *byte6 &= ~bit6; |
| 117 | |
| 118 | v6it++; |
| 119 | } |
| 120 | |
| 121 | /* Print the subnet prefix. */ |
| 122 | if (inet_ntop(AF_INET6, &v6, v6str, sizeof(v6str)) == NULL) |
| 123 | print_error(); |
| 124 | printf("%s/%lu\n", v6str, mask); |
| 125 | return 0; |
| 126 | } |
| 127 | |