1/* $NetBSD: type_ipv4.c,v 1.9 2004/11/24 11:57:09 blymn 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 <sys/cdefs.h> 33__RCSID("$NetBSD: type_ipv4.c,v 1.9 2004/11/24 11:57:09 blymn 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 */ 60static int 61ipv4_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 fprintf(dbg, "ipv4_check_field: enter with args of %s\n", 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 fprintf(dbg, "ipv4_check_field: buf0 set to %s\n", buf); 172 fprintf(dbg, "ipv4_check_field: buf1 set to %s\n", 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 */ 189static int 190ipv4_check_char(/* ARGSUSED1 */ int c, char *args) 191{ 192 return (isxdigit(c) || (c == '.') || (tolower(c) == 'x') || 193 (c == '/'))? TRUE : FALSE; 194} 195 196static 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 209FIELDTYPE *TYPE_IPV4 = &builtin_ipv4; 210 211 212