1 /* $NetBSD: type_ipv4.c,v 1.11 2016/03/09 19:47:13 christos Exp $ */ 2 3 /*- 4 * Copyright (c) 1998-1999 Brett Lymn 5 * (blymn (at) baea.com.au, brett_lymn (at) yahoo.com.au) 6 * All rights reserved. 7 * 8 * This code has been donated to The NetBSD Foundation by the Author. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 * 29 * 30 */ 31 32 #include <sys/cdefs.h> 33 __RCSID("$NetBSD: type_ipv4.c,v 1.11 2016/03/09 19:47:13 christos Exp $"); 34 35 #include <string.h> 36 #include <stdlib.h> 37 #include <ctype.h> 38 #include <errno.h> 39 #include <limits.h> 40 #include "form.h" 41 #include "internals.h" 42 43 /* 44 * The IP v4 address type handling. 45 */ 46 47 /* 48 * define the styles of address we can have, they are: 49 * FORMI_DOTTED_QUAD address of form aaa.bbb.ccc.ddd 50 * FORMI_HEX address of form 0xaabbccdd 51 * FORMI_CLASSLESS address of form aaa.bbb.ccc.ddd/ee 52 */ 53 #define FORMI_DOTTED_QUAD 0 54 #define FORMI_HEX 1 55 #define FORMI_CLASSLESS 2 56 57 /* 58 * Check the contents of the field buffer are a valid IPv4 address only. 59 */ 60 static int 61 ipv4_check_field(FIELD *field, char *args) 62 { 63 char *buf, *buf1, *keeper, *p, *slash; 64 unsigned int vals[4], style, start, mask; 65 unsigned long hex_val, working; 66 int i; 67 68 if (args == NULL) 69 return FALSE; 70 71 if (asprintf(&keeper, "%s", args) < 0) 72 return FALSE; 73 74 #ifdef DEBUG 75 _formi_dbg_printf("%s: enter with args of %s\n", __func__, keeper); 76 #endif 77 style = FORMI_DOTTED_QUAD; 78 buf = keeper; 79 hex_val = 0; 80 mask = 0; 81 82 if ((slash = index(buf, '/')) != NULL) 83 style = FORMI_CLASSLESS; 84 else { 85 start = _formi_skip_blanks(buf, 0); 86 if ((buf[start] != '\0') && (buf[start + 1] != '\0') && 87 (buf[start] == '0') && ((buf[start + 1] == 'x') || 88 (buf[start + 1] == 'X'))) 89 style = FORMI_HEX; 90 } 91 92 switch (style) { 93 case FORMI_CLASSLESS: 94 *slash = '\0'; 95 slash++; 96 mask = atoi(slash); 97 if (mask > 32) 98 goto FAIL; 99 /* FALLTHROUGH */ 100 101 case FORMI_DOTTED_QUAD: 102 for (i = 0; i < 4; i++) { 103 p = strsep(&buf, "."); 104 if ((p == NULL) || (*p == '\0')) 105 goto FAIL; 106 vals[i] = atoi(p); 107 if (vals[i] > 255) 108 goto FAIL; 109 } 110 break; 111 112 113 case FORMI_HEX: 114 errno = 0; 115 hex_val = strtoul(buf, NULL, 16); 116 if ((hex_val == ULONG_MAX) && (errno == ERANGE)) 117 goto FAIL; 118 119 working = hex_val; 120 for (i = 3; i >= 0; i--) { 121 vals[i] = (unsigned int)(working & 0xffUL); 122 working = working >> 8; 123 } 124 break; 125 126 } 127 128 free(keeper); 129 130 buf1 = NULL; 131 132 switch (style) { 133 case FORMI_DOTTED_QUAD: 134 if (asprintf(&buf, "%d.%d.%d.%d", vals[0], vals[1], vals[2], 135 vals[3]) < 0) 136 return FALSE; 137 if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1], 138 vals[2], vals[3]) < 0) 139 return FALSE; 140 break; 141 142 case FORMI_CLASSLESS: 143 if (asprintf(&buf, "%d.%d.%d.%d/%d", vals[0], vals[1], 144 vals[2], vals[3], mask) < 0) 145 return FALSE; 146 if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1], 147 vals[2], vals[3]) < 0) 148 return FALSE; 149 break; 150 151 case FORMI_HEX: 152 if (asprintf(&buf, "0x%.8lx", hex_val) < 0) 153 return FALSE; 154 if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1], 155 vals[2], vals[3]) < 0) 156 return FALSE; 157 break; 158 } 159 160 /* re-set the field buffer to be the reformatted IPv4 address */ 161 set_field_buffer(field, 0, buf); 162 163 /* 164 * Set the field buffer 1 to the dotted quad format regardless 165 * of the input format, only if buffer 1 exists. 166 */ 167 if (field->nbuf > 1) 168 set_field_buffer(field, 1, buf1); 169 170 #ifdef DEBUG 171 _formi_dbg_printf("%s: buf0 set to %s\n", __func__, buf); 172 _formi_dbg_printf("%s: buf1 set to %s\n", __func__, buf1); 173 #endif 174 free(buf); 175 free(buf1); 176 177 return TRUE; 178 179 /* bail out point if we got a bad entry */ 180 FAIL: 181 free(keeper); 182 return FALSE; 183 184 } 185 186 /* 187 * Check the given character is numeric, return TRUE if it is. 188 */ 189 static int 190 ipv4_check_char(/* ARGSUSED1 */ int c, char *args) 191 { 192 return (isxdigit(c) || (c == '.') || (tolower(c) == 'x') || 193 (c == '/'))? TRUE : FALSE; 194 } 195 196 static FIELDTYPE builtin_ipv4 = { 197 _TYPE_IS_BUILTIN, /* flags */ 198 0, /* refcount */ 199 NULL, /* link */ 200 NULL, /* make_args */ 201 NULL, /* copy_args */ 202 NULL, /* free_args */ 203 ipv4_check_field, /* field_check */ 204 ipv4_check_char, /* char_check */ 205 NULL, /* next_choice */ 206 NULL /* prev_choice */ 207 }; 208 209 FIELDTYPE *TYPE_IPV4 = &builtin_ipv4; 210 211 212