| /** @file |
| |
| Loading @c IpMap from a configuration file. |
| |
| @section license License |
| |
| Licensed to the Apache Software Foundation (ASF) under one |
| or more contributor license agreements. See the NOTICE file |
| distributed with this work for additional information |
| regarding copyright ownership. The ASF licenses this file |
| to you under the Apache License, Version 2.0 (the |
| "License"); you may not use this file except in compliance |
| with the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| // Copied from IPRange.cc for backwards compatibility. |
| |
| #include "tscore/IpMap.h" |
| #include "tscore/IpMapConf.h" |
| #include "tscore/ink_memory.h" |
| |
| static size_t const ERR_STRING_LEN = 256; |
| static size_t const MAX_LINE_SIZE = 2048; |
| |
| // Returns 0 if successful, 1 if failed |
| // line Input text (source line). |
| // n Amount of data in @a line. |
| // i [in,out] Offset in line. |
| // addr [out] Destination for address. |
| // err Buffer for error string (must be ERR_STRING_LEN big). |
| int |
| read_addr(char *line, int n, int *i, sockaddr *addr, char *err) |
| { |
| int k; |
| char dst[INET6_ADDRSTRLEN]; |
| char *src = line + *i; |
| bool bracketed_p = false; |
| |
| // Allow enclosing brackets to be more consistent but |
| // don't bother passing it to @c ntop. |
| if ((*i < n) && ('[' == *src)) { |
| ++*i, ++src, bracketed_p = true; |
| } |
| |
| for (k = 0; k < INET6_ADDRSTRLEN && *i < n && (isxdigit(*src) || '.' == *src || ':' == *src); ++k, ++*i, ++src) { |
| dst[k] = *src; |
| } |
| |
| if (bracketed_p && (!(*i < n) || (']' != *src))) { |
| snprintf(err, ERR_STRING_LEN, "Unclosed brackets"); |
| return EINVAL; |
| } |
| |
| if (k == sizeof(dst)) { |
| snprintf(err, ERR_STRING_LEN, "IP address too long"); |
| return EINVAL; |
| } |
| |
| dst[k] = '\0'; |
| if (0 != ats_ip_pton(dst, addr)) { |
| snprintf(err, ERR_STRING_LEN, "IP address '%s' improperly formatted", dst); |
| return EINVAL; |
| } |
| return 0; |
| } |
| |
| char * |
| Load_IpMap_From_File(IpMap *map, int fd, const char *key_str) |
| { |
| char *zret = nullptr; |
| int fd2 = dup(fd); // dup to avoid closing the original file. |
| FILE *f = nullptr; |
| |
| if (fd2 >= 0) { |
| f = fdopen(fd2, "r"); |
| } |
| |
| if (f != nullptr) { |
| zret = Load_IpMap_From_File(map, f, key_str); |
| fclose(f); |
| } else { |
| zret = static_cast<char *>(ats_malloc(ERR_STRING_LEN)); |
| snprintf(zret, ERR_STRING_LEN, "Unable to reopen file descriptor as stream %d:%s", errno, strerror(errno)); |
| } |
| return zret; |
| } |
| |
| // Skip space in line, returning true if more data is available |
| // (not end of line). |
| // |
| // line Source line. |
| // n Line length. |
| // offset Current offset |
| static inline bool |
| skip_space(char *line, int n, int &offset) |
| { |
| while (offset < n && isspace(line[offset])) { |
| ++offset; |
| } |
| return offset < n; |
| } |
| |
| // Returns 0 if successful, error string otherwise |
| char * |
| Load_IpMap_From_File(IpMap *map, FILE *f, const char *key_str) |
| { |
| int i, n, line_no; |
| int key_len = strlen(key_str); |
| IpEndpoint laddr, raddr; |
| char line[MAX_LINE_SIZE]; |
| char err_buff[ERR_STRING_LEN]; |
| |
| // First hardcode 127.0.0.1 into the table |
| map->mark(INADDR_LOOPBACK); |
| |
| line_no = 0; |
| while (fgets(line, MAX_LINE_SIZE, f)) { |
| ++line_no; |
| n = strlen(line); |
| // Find first white space which terminates the line key. |
| for (i = 0; i < n && !isspace(line[i]); ++i) { |
| ; |
| } |
| if (i != key_len || 0 != strncmp(line, key_str, key_len)) { |
| continue; |
| } |
| // Now look for IP address |
| while (true) { |
| if (!skip_space(line, n, i)) { |
| break; |
| } |
| |
| if (0 != read_addr(line, n, &i, &laddr.sa, err_buff)) { |
| char *error_str = static_cast<char *>(ats_malloc(ERR_STRING_LEN)); |
| snprintf(error_str, ERR_STRING_LEN, "Invalid input configuration (%s) at line %d offset %d - '%s'", err_buff, line_no, i, |
| line); |
| return error_str; |
| } |
| |
| if (!skip_space(line, n, i) || line[i] == ',') { |
| // You have read an IP address. Enter it in the table |
| map->mark(&laddr); |
| if (i == n) { |
| break; |
| } else { |
| ++i; |
| } |
| } else if (line[i] == '-') { |
| // What you have just read is the start of the range, |
| // Now, read the end of the IP range |
| ++i; |
| if (!skip_space(line, n, i)) { |
| char *error_str = static_cast<char *>(ats_malloc(ERR_STRING_LEN)); |
| snprintf(error_str, ERR_STRING_LEN, "Invalid input (unterminated range) at line %d offset %d - '%s'", line_no, i, line); |
| return error_str; |
| } else if (0 != read_addr(line, n, &i, &raddr.sa, err_buff)) { |
| char *error_str = static_cast<char *>(ats_malloc(ERR_STRING_LEN)); |
| snprintf(error_str, ERR_STRING_LEN, "Invalid input (%s) at line %d offset %d - '%s'", err_buff, line_no, i, line); |
| return error_str; |
| } |
| map->mark(&laddr.sa, &raddr.sa); |
| if (!skip_space(line, n, i)) { |
| break; |
| } |
| if (line[i] != ',') { |
| char *error_str = static_cast<char *>(ats_malloc(ERR_STRING_LEN)); |
| snprintf(error_str, ERR_STRING_LEN, "Invalid input (expecting comma) at line %d offset %d - '%s'", line_no, i, line); |
| return error_str; |
| } |
| ++i; |
| } else { |
| char *error_str = static_cast<char *>(ats_malloc(ERR_STRING_LEN)); |
| snprintf(error_str, ERR_STRING_LEN, "Invalid input (expecting dash or comma) at line %d offset %d", line_no, i); |
| return error_str; |
| } |
| } |
| } |
| return nullptr; |
| } |