1 /* $NetBSD: type_ipv4.c,v 1.6 2001/06/13 10:45:59 wiz Exp $ */ 2 3 /*- 4 * Copyright (c) 1998-1999 Brett Lymn 5 * (blymn@baea.com.au, brett_lymn@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 <string.h> 33 #include <stdlib.h> 34 #include <ctype.h> 35 #include <errno.h> 36 #include <stdlib.h> 37 #include <limits.h> 38 #include "form.h" 39 #include "internals.h" 40 41 /* 42 * The IP v4 address type handling. 43 */ 44 45 /* 46 * define the styles of address we can have, they are: 47 * FORMI_DOTTED_QUAD address of form aaa.bbb.ccc.ddd 48 * FORMI_HEX address of form 0xaabbccdd 49 * FORMI_CLASSLESS address of form aaa.bbb.ccc.ddd/ee 50 */ 51 #define FORMI_DOTTED_QUAD 0 52 #define FORMI_HEX 1 53 #define FORMI_CLASSLESS 2 54 55 /* 56 * Check the contents of the field buffer are a valid IPv4 address only. 57 */ 58 static int 59 ipv4_check_field(FIELD *field, char *args) 60 { 61 char *buf, *buf1, *keeper, *p, *slash; 62 unsigned int vals[4], style, start, mask; 63 unsigned long hex_val, working; 64 int i; 65 66 if (args == NULL) 67 return FALSE; 68 69 if (asprintf(&keeper, "%s", args) < 0) 70 return FALSE; 71 72 #ifdef DEBUG 73 fprintf(dbg, "ipv4_check_field: enter with args of %s\n", keeper); 74 #endif 75 style = FORMI_DOTTED_QUAD; 76 buf = keeper; 77 78 if ((slash = index(buf, '/')) != NULL) 79 style = FORMI_CLASSLESS; 80 else { 81 start = _formi_skip_blanks(buf, 0); 82 if ((buf[start] != '\0') && (buf[start + 1] != '\0') && 83 (buf[start] == '0') && ((buf[start + 1] == 'x') || 84 (buf[start + 1] == 'X'))) 85 style = FORMI_HEX; 86 } 87 88 switch (style) { 89 case FORMI_CLASSLESS: 90 *slash = '\0'; 91 slash++; 92 mask = atoi(slash); 93 if (mask > 32) 94 goto FAIL; 95 /* FALLTHROUGH */ 96 97 case FORMI_DOTTED_QUAD: 98 for (i = 0; i < 4; i++) { 99 p = strsep(&buf, "."); 100 if ((p == NULL) || (*p == '\0')) 101 goto FAIL; 102 vals[i] = atoi(p); 103 if (vals[i] > 255) 104 goto FAIL; 105 } 106 break; 107 108 109 case FORMI_HEX: 110 hex_val = strtoul(buf, NULL, 16); 111 if ((hex_val == ULONG_MAX) && (errno == ERANGE)) 112 goto FAIL; 113 114 working = hex_val; 115 for (i = 3; i >= 0; i--) { 116 vals[i] = (unsigned int)(working & 0xffUL); 117 working = working >> 8; 118 } 119 break; 120 121 } 122 123 free(keeper); 124 125 buf1 = NULL; 126 127 switch (style) { 128 case FORMI_DOTTED_QUAD: 129 if (asprintf(&buf, "%d.%d.%d.%d", vals[0], vals[1], vals[2], 130 vals[3]) < 0) 131 return FALSE; 132 if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1], 133 vals[2], vals[3]) < 0) 134 return FALSE; 135 break; 136 137 case FORMI_CLASSLESS: 138 if (asprintf(&buf, "%d.%d.%d.%d/%d", vals[0], vals[1], 139 vals[2], vals[3], mask) < 0) 140 return FALSE; 141 if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1], 142 vals[2], vals[3]) < 0) 143 return FALSE; 144 break; 145 146 case FORMI_HEX: 147 if (asprintf(&buf, "0x%.8lx", hex_val) < 0) 148 return FALSE; 149 if (asprintf(&buf1, "%d.%d.%d.%d", vals[0], vals[1], 150 vals[2], vals[3]) < 0) 151 return FALSE; 152 break; 153 } 154 155 /* re-set the field buffer to be the reformatted IPv4 address */ 156 set_field_buffer(field, 0, buf); 157 158 /* 159 * Set the field buffer 1 to the dotted quad format regardless 160 * of the input format, only if buffer 1 exists. 161 */ 162 if (field->nbuf > 1) 163 set_field_buffer(field, 1, buf1); 164 165 #ifdef DEBUG 166 fprintf(dbg, "ipv4_check_field: buf0 set to %s\n", buf); 167 fprintf(dbg, "ipv4_check_field: buf1 set to %s\n", buf1); 168 #endif 169 free(buf); 170 free(buf1); 171 172 return TRUE; 173 174 /* bail out point if we got a bad entry */ 175 FAIL: 176 free(keeper); 177 return FALSE; 178 179 } 180 181 /* 182 * Check the given character is numeric, return TRUE if it is. 183 */ 184 static int 185 ipv4_check_char(/* ARGSUSED1 */ int c, char *args) 186 { 187 return (isxdigit(c) || (c == '.') || (tolower(c) == 'x') || 188 (c == '/'))? TRUE : FALSE; 189 } 190 191 static FIELDTYPE builtin_ipv4 = { 192 _TYPE_IS_BUILTIN, /* flags */ 193 0, /* refcount */ 194 NULL, /* link */ 195 NULL, /* make_args */ 196 NULL, /* copy_args */ 197 NULL, /* free_args */ 198 ipv4_check_field, /* field_check */ 199 ipv4_check_char, /* char_check */ 200 NULL, /* next_choice */ 201 NULL /* prev_choice */ 202 }; 203 204 FIELDTYPE *TYPE_IPV4 = &builtin_ipv4; 205 206 207