Author: ae Date: Tue Apr 2 12:50:01 2019 New Revision: 345797 URL: https://svnweb.freebsd.org/changeset/base/345797
Log: Add IPv6 transport for bsnmp. This patch adds a new table begemotSnmpdTransInetTable that uses the InetAddressType textual convention and can be used to create listening ports for IPv4, IPv6, zoned IPv6 and based on DNS names. It also supports future extension beyond UDP by adding a protocol identifier to the table index. In order to support this gensnmptree had to be modified. Submitted by: harti MFC after: 1 month Relnotes: yes Differential Revision: https://reviews.freebsd.org/D16654 Added: head/contrib/bsnmp/snmpd/trans_inet.c head/contrib/bsnmp/snmpd/trans_inet.h Modified: head/contrib/bsnmp/gensnmptree/gensnmptree.1 head/contrib/bsnmp/gensnmptree/gensnmptree.c head/contrib/bsnmp/lib/snmpclient.c head/contrib/bsnmp/lib/snmpclient.h head/contrib/bsnmp/lib/tc.def head/contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt head/contrib/bsnmp/snmpd/main.c head/contrib/bsnmp/snmpd/snmpd.config head/contrib/bsnmp/snmpd/snmpd.h head/contrib/bsnmp/snmpd/snmpmod.h head/contrib/bsnmp/snmpd/trans_lsock.c head/contrib/bsnmp/snmpd/trans_udp.c head/contrib/bsnmp/snmpd/tree.def head/lib/libbsnmp/libbsnmp/Makefile head/usr.sbin/bsnmpd/bsnmpd/Makefile head/usr.sbin/bsnmpd/bsnmpd/snmpd.config Modified: head/contrib/bsnmp/gensnmptree/gensnmptree.1 ============================================================================== --- head/contrib/bsnmp/gensnmptree/gensnmptree.1 Tue Apr 2 12:02:35 2019 (r345796) +++ head/contrib/bsnmp/gensnmptree/gensnmptree.1 Tue Apr 2 12:50:01 2019 (r345797) @@ -31,7 +31,7 @@ .\" .\" $Begemot: gensnmptree.1 383 2006-05-30 07:40:49Z brandt_h $ .\" -.Dd June 29, 2018 +.Dd April 2, 2019 .Dt GENSNMPTREE 1 .Os .Sh NAME @@ -100,25 +100,11 @@ is the length of the OID. is the last component of the OID. .El .It Fl F -Together with -.Fl E -causes -.Nm -instead of the generation of enum definitions the generation of -functions for checking a value to be one of the enumeration variants and -for conversion between strings and the enum. The file is sent to standard -output and is meant to be included into a C-file for compilation. +emit definitions for C-functions includeable in a C-file that do some basic +stuff on enums like value checking and conversion between value and strings. .It Fl f -This flag can be used together with -.Fl E -or when generating the tree files. It causes -.Nm -to emit static inline functions for checking a value to be one of the -enumeration values and for conversion between strings and the enum. -If used when generating the tree files, the preprocessor symbol -.Ar SNMPTREE_TYPES -must be defined when including the tree header file for these definitions -to become visible. +emit definitions for inline C-functions that do some basic +stuff on enums like value checking and conversion between value and strings. .It Fl h Print a short help page. .It Fl I Ar directory @@ -136,36 +122,6 @@ Instead of normal output print the resulting tree. Prefix the file names and the table name with .Ar prefix . .El -.Pp -The following functions are generated by -.Fl f -or -.Fl F : -.Pp -.Ft static inline int -.Fn isok_EnumName "enum EnumName" ; -.Pp -.Ft static inline const char * -.Fn tostr_EnumName "enum EnumName" ; -.Pp -.Ft static inline int -.Fn fromstr_EnumName "const char *" "enum EnumName *" ; -.Pp -The -.Fa EnumName -is replaced with the enumeration name. -.Fn isok_EnumName -returns 1 if the argument is one of the valid enum values and 0 otherwise. -.Fn tostr_EnumName -returns a string representation of the enumeration value. -If the values is not one of the legal values -.Ar EnumName??? -is returned. -.Fn fromstr_EnumName -returns 1 if the string represents one of the legal enumeration values and -0 otherwise. -If 1 is return the variable pointed to by the second argument is set to -the enumeration value. .Sh MIBS The syntax of the MIB description file can formally be specified as follows: .Bd -unfilled -offset indent Modified: head/contrib/bsnmp/gensnmptree/gensnmptree.c ============================================================================== --- head/contrib/bsnmp/gensnmptree/gensnmptree.c Tue Apr 2 12:02:35 2019 (r345796) +++ head/contrib/bsnmp/gensnmptree/gensnmptree.c Tue Apr 2 12:50:01 2019 (r345797) @@ -110,7 +110,6 @@ static int debug; static const char usgtxt[] = "\ Generate SNMP tables.\n\ -$Id$\n\ usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\ [name]...\n\ options:\n\ @@ -127,6 +126,37 @@ options:\n\ -t generate a .def file\n\ "; +/** + * Program operation. + */ +enum op { + /** generate the tree */ + OP_GEN, + + /** extract OIDs */ + OP_EXTRACT, + + /** print the parsed tree */ + OP_TREE, + + /** extract enums */ + OP_ENUMS, +}; + +/** + * Which functions to create. + */ +enum gen_funcs { + /** none */ + GEN_FUNCS_NONE, + + /** functions for header files */ + GEN_FUNCS_H, + + /** functions for C files */ + GEN_FUNCS_C, +}; + /* * A node in the OID tree */ @@ -162,15 +192,18 @@ struct node { uint32_t index; /* index for table entry */ char *func; /* function for tables */ struct node_list subs; + char *subtypes[SNMP_INDEXES_MAX]; } entry; struct leaf { enum snmp_syntax syntax; /* syntax for this leaf */ char *func; /* function name */ + char *subtype; /* subtype */ } leaf; struct column { enum snmp_syntax syntax; /* syntax for this column */ + char *subtype; /* subtype */ } column; } u; }; @@ -214,7 +247,7 @@ xalloc(size_t size) { void *ptr; - if ((ptr = malloc(size)) == NULL) + if ((ptr = calloc(1, size)) == NULL) err(1, "allocing %zu bytes", size); return (ptr); @@ -710,12 +743,14 @@ make_type(const char *s) * token. */ static u_int -parse_type(enum tok *tok, struct type *t, const char *vname) +parse_type(enum tok *tok, struct type *t, const char *vname, char **subtype) { u_int syntax; struct enums *e; syntax = val; + if (subtype != NULL) + *subtype = NULL; if (*tok == TOK_ENUM || *tok == TOK_BITS) { if (t == NULL && vname != NULL) { @@ -759,6 +794,8 @@ parse_type(enum tok *tok, struct type *t, const char * if ((*tok = gettoken()) == '|') { if (gettoken() != TOK_STR) report("subtype expected after '|'"); + if (subtype != NULL) + *subtype = savetok(); *tok = gettoken(); } } @@ -794,18 +831,21 @@ parse(enum tok tok) if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE || tok == TOK_ENUM || tok == TOK_BITS) { /* LEAF or COLUM */ - u_int syntax = parse_type(&tok, NULL, node->name); + char *subtype; + u_int syntax = parse_type(&tok, NULL, node->name, &subtype); if (tok == TOK_STR) { /* LEAF */ node->type = NODE_LEAF; node->u.leaf.func = savetok(); node->u.leaf.syntax = syntax; + node->u.leaf.subtype = subtype; tok = gettoken(); } else { /* COLUMN */ node->type = NODE_COLUMN; node->u.column.syntax = syntax; + node->u.column.subtype = subtype; } while (tok != ')') { @@ -825,9 +865,12 @@ parse(enum tok tok) tok = gettoken(); while (tok == TOK_TYPE || tok == TOK_DEFTYPE || tok == TOK_ENUM || tok == TOK_BITS) { - u_int syntax = parse_type(&tok, NULL, node->name); - if (index_count++ == SNMP_INDEXES_MAX) + char *subtype; + u_int syntax = parse_type(&tok, NULL, node->name, + &subtype); + if (index_count == SNMP_INDEXES_MAX) report("too many table indexes"); + node->u.entry.subtypes[index_count++] = subtype; node->u.entry.index |= syntax << (SNMP_INDEX_SHIFT * index_count); } @@ -882,7 +925,8 @@ parse_top(enum tok tok) tok = gettoken(); t->is_enum = (tok == TOK_ENUM); t->is_bits = (tok == TOK_BITS); - t->syntax = parse_type(&tok, t, NULL); + + t->syntax = parse_type(&tok, t, NULL, NULL); pushback(tok); return (NULL); @@ -903,7 +947,7 @@ parse_top(enum tok tok) * Generate the C-code table part for one node. */ static void -gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx, +gen_node(FILE *fp, const struct node *np, struct asn_oid *oid, u_int idx, const char *func) { u_int n; @@ -1008,7 +1052,7 @@ gen_node(FILE *fp, struct node *np, struct asn_oid *oi * Generate the header file with the function declarations. */ static void -gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func) +gen_header(FILE *fp, const struct node *np, u_int oidlen, const char *func) { char f[MAXSTR + 4]; struct node *sub; @@ -1058,7 +1102,7 @@ gen_header(FILE *fp, struct node *np, u_int oidlen, co * Generate the OID table. */ static void -gen_table(FILE *fp, struct node *node) +gen_table(FILE *fp, const struct node *node) { struct asn_oid oid; @@ -1067,7 +1111,6 @@ gen_table(FILE *fp, struct node *node) #ifdef HAVE_STDINT_H fprintf(fp, "#include <stdint.h>\n"); #endif - fprintf(fp, "#include <string.h>\n"); if (localincs) { fprintf(fp, "#include \"asn1.h\"\n"); fprintf(fp, "#include \"snmp.h\"\n"); @@ -1118,6 +1161,8 @@ gen_tree(const struct node *np, int level) case NODE_LEAF: print_syntax(np->u.leaf.syntax); + if (np->u.leaf.subtype != NULL) + printf(" | %s", np->u.leaf.subtype); printf(" %s%s%s)\n", np->u.leaf.func, (np->flags & FL_GET) ? " GET" : "", (np->flags & FL_SET) ? " SET" : ""); @@ -1137,8 +1182,11 @@ gen_tree(const struct node *np, int level) case NODE_ENTRY: printf(" :"); - for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) + for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) { print_syntax(SNMP_INDEX(np->u.entry.index, i)); + if (np->u.entry.subtypes[i] != NULL) + printf(" | %s", np->u.entry.subtypes[i]); + } printf(" %s\n", np->u.entry.func); TAILQ_FOREACH(sp, &np->u.entry.subs, link) gen_tree(sp, level + 1); @@ -1147,6 +1195,8 @@ gen_tree(const struct node *np, int level) case NODE_COLUMN: print_syntax(np->u.column.syntax); + if (np->u.column.subtype != NULL) + printf(" | %s", np->u.column.subtype); printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", (np->flags & FL_SET) ? " SET" : ""); break; @@ -1194,15 +1244,6 @@ extract(FILE *fp, const struct node *np, struct asn_oi return (1); } -/** - * Extract the named OID. - * - * \param fp file to extract to - * \param root root of the tree - * \param object name of the object to extract - * - * \return 0 on success, -1 if the object was not found - */ static int gen_extract(FILE *fp, const struct node *root, char *object) { @@ -1391,45 +1432,6 @@ unminus(FILE *fp, const char *s) } /** - * Generate a definition for the enum packed into a guard against multiple - * definitions. - * - * \param fp file to write definition to - * \param t type - */ -static void -gen_enum(FILE *fp, const struct type *t) -{ - const struct enums *e; - long min = LONG_MAX; - - fprintf(fp, "\n"); - fprintf(fp, "#ifndef %s_defined__\n", t->name); - fprintf(fp, "#define %s_defined__\n", t->name); - fprintf(fp, "/*\n"); - fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno); - fprintf(fp, " */\n"); - fprintf(fp, "enum %s {\n", t->name); - TAILQ_FOREACH(e, &t->enums, link) { - fprintf(fp, "\t%s_", t->name); - unminus(fp, e->name); - fprintf(fp, " = %ld,\n", e->value); - if (e->value < min) - min = e->value; - } - fprintf(fp, "};\n"); - fprintf(fp, "#define STROFF_%s %ld\n", t->name, min); - fprintf(fp, "#define STRING_%s \\\n", t->name); - TAILQ_FOREACH(e, &t->enums, link) { - fprintf(fp, "\t[%ld] = \"%s_", e->value - min, t->name); - unminus(fp, e->name); - fprintf(fp, "\",\\\n"); - } - fprintf(fp, "\n"); - fprintf(fp, "#endif /* %s_defined__ */\n", t->name); -} - -/** * Generate helper functions for an enum. * * We always generate a switch statement for the isok function. The compiler @@ -1494,6 +1496,54 @@ gen_enum_funcs(FILE *fp, const struct type *t, int cco } /** + * Generate a definition for the enum packed into a guard against multiple + * definitions. + * + * \param fp file to write definition to + * \param t type + * \param dof generate functions too + */ +static void +gen_enum(FILE *fp, const struct type *t, int dof) +{ + const struct enums *e; + long min = LONG_MAX; + + fprintf(fp, "\n"); + fprintf(fp, "#ifndef %s_defined__\n", t->name); + fprintf(fp, "#define %s_defined__\n", t->name); + fprintf(fp, "/*\n"); + fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno); + fprintf(fp, " */\n"); + fprintf(fp, "enum %s {\n", t->name); + TAILQ_FOREACH(e, &t->enums, link) { + fprintf(fp, "\t%s_", t->name); + unminus(fp, e->name); + fprintf(fp, " = %ld,\n", e->value); + if (e->value < min) + min = e->value; + } + fprintf(fp, "};\n"); + fprintf(fp, "#define STROFF_%s %ld\n", t->name, min); + fprintf(fp, "#define STRING_%s \\\n", t->name); + TAILQ_FOREACH(e, &t->enums, link) { + fprintf(fp, "\t[%ld] = \"%s_", e->value - min, t->name); + unminus(fp, e->name); + fprintf(fp, "\",\\\n"); + } + fprintf(fp, "\n"); + if (dof) { + fprintf(fp, "#ifdef SNMPENUM_FUNCS\n"); + fprintf(fp, "\n"); + gen_enum_funcs(fp, t, 0); + fprintf(fp, "\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, "\n"); + } + fprintf(fp, "#endif /* %s_defined__ */\n", t->name); +} + +/** * Generate helper functions for an enum. This generates code for a c file. * * \param fp file to write to @@ -1529,6 +1579,16 @@ gen_all_enum_funcs(FILE *fp, int ccode) gen_enum_funcs(fp, t, ccode); } +static void +gen_enums(FILE *fp, int dof) +{ + const struct type *t; + + LIST_FOREACH(t, &types, link) + if (t->is_enum || t->is_bits) + gen_enum(fp, t, dof); +} + /** * Extract a given enum to the specified file and optionally generate static * inline helper functions for them. @@ -1546,9 +1606,7 @@ extract_enum(FILE *fp, const char *name, int gen_funcs LIST_FOREACH(t, &types, link) if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { - gen_enum(fp, t); - if (gen_funcs) - gen_enum_funcs(fp, t, 0); + gen_enum(fp, t, gen_funcs); return (0); } return (-1); @@ -1567,11 +1625,8 @@ extract_all_enums(FILE *fp, int gen_funcs) const struct type *t; LIST_FOREACH(t, &types, link) - if (t->is_enum || t->is_bits) { - gen_enum(fp, t); - if (gen_funcs) - gen_enum_funcs(fp, t, 0); - } + if (t->is_enum || t->is_bits) + gen_enum(fp, t, gen_funcs); } /** @@ -1579,13 +1634,12 @@ extract_all_enums(FILE *fp, int gen_funcs) * * \param argc number of arguments * \param argv arguments (enum names) - * \param gen_funcs_h generate functions into the header file - * \param gen_funcs_c generate a .c file with functions + * \param gen_funcs which functions to generate */ static void -make_enums(int argc, char *argv[], int gen_funcs_h, int gen_funcs_c) +make_enums(int argc, char *argv[], enum gen_funcs gen_funcs) { - if (gen_funcs_c) { + if (gen_funcs == GEN_FUNCS_C) { if (argc == 0) gen_all_enum_funcs(stdout, 1); else { @@ -1595,30 +1649,58 @@ make_enums(int argc, char *argv[], int gen_funcs_h, in } } else { if (argc == 0) - extract_all_enums(stdout, gen_funcs_h); + extract_all_enums(stdout, gen_funcs == GEN_FUNCS_H); else { for (int i = 0; i < argc; i++) - if (extract_enum(stdout, argv[i], gen_funcs_h)) + if (extract_enum(stdout, argv[i], + gen_funcs == GEN_FUNCS_H)) errx(1, "enum not found: %s", argv[i]); } } } +/** + * Produce the operation tables for the daemon or a module. + * + * \param root tree root + * \param gen_funcs generate enum funcs + */ +static void +make_table(const struct node *root, int gen_funcs) +{ + FILE *fp; + + char fname[MAXPATHLEN + 1]; + sprintf(fname, "%stree.h", file_prefix); + if ((fp = fopen(fname, "w")) == NULL) + err(1, "%s: ", fname); + gen_header(fp, root, PREFIX_LEN, NULL); + + fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n"); + gen_enums(fp, gen_funcs); + fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n"); + + fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); + fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); + + fclose(fp); + + sprintf(fname, "%stree.c", file_prefix); + if ((fp = fopen(fname, "w")) == NULL) + err(1, "%s: ", fname); + gen_table(fp, root); + fclose(fp); +} + int main(int argc, char *argv[]) { - int do_extract = 0; - int do_tree = 0; - int do_enums = 0; - int gen_funcs_h = 0; - int gen_funcs_c = 0; - int opt; - struct node *root; - char fname[MAXPATHLEN + 1]; - int tok; - FILE *fp; + enum op op = OP_GEN; + enum gen_funcs gen_funcs = GEN_FUNCS_NONE; + char *infile = NULL; + int opt; while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF) switch (opt) { @@ -1627,19 +1709,29 @@ main(int argc, char *argv[]) break; case 'E': - do_enums = 1; + if (op != OP_GEN && op != OP_ENUMS) + errx(1, "-E conflicts with earlier options"); + op = OP_ENUMS; break; case 'e': - do_extract = 1; + if (op != OP_GEN && op != OP_EXTRACT) + errx(1, "-e conflicts with earlier options"); + op = OP_EXTRACT; break; case 'F': - gen_funcs_c = 1; + if (gen_funcs != GEN_FUNCS_NONE && + gen_funcs != GEN_FUNCS_C) + errx(1, "-F conflicts with -f"); + gen_funcs = GEN_FUNCS_C; break; case 'f': - gen_funcs_h = 1; + if (gen_funcs != GEN_FUNCS_NONE && + gen_funcs != GEN_FUNCS_H) + errx(1, "-f conflicts with -F"); + gen_funcs = GEN_FUNCS_H; break; case 'h': @@ -1666,75 +1758,61 @@ main(int argc, char *argv[]) break; case 't': - do_tree = 1; + if (op != OP_GEN && op != OP_TREE) + errx(1, "-t conflicts with earlier options"); + op = OP_TREE; break; } - if (do_extract + do_tree + do_enums > 1) - errx(1, "conflicting options -e/-t/-E"); - if (!do_extract && !do_enums && argc != optind) - errx(1, "no arguments allowed"); - if (do_extract && argc == optind) - errx(1, "no objects specified"); + argc -= optind; + argv += optind; - if ((gen_funcs_h || gen_funcs_c) && (do_extract || do_tree)) - errx(1, "-f and -F not allowed with -e or -t"); - if (gen_funcs_c && !do_enums) - errx(1, "-F requires -E"); - if (gen_funcs_h && gen_funcs_c) - errx(1, "-f and -F are mutually exclusive"); - + /* open input */ if (infile == NULL) { input_new(stdin, NULL, "<stdin>"); } else { + FILE *fp; if ((fp = fopen(infile, "r")) == NULL) err(1, "%s", infile); input_new(fp, NULL, infile); } - root = parse_top(gettoken()); + /* parse and check input */ + struct node *root = parse_top(gettoken()); + + int tok; while ((tok = gettoken()) != TOK_EOF) merge(&root, parse_top(tok)); if (root) check_tree(root); - if (do_extract) { - while (optind < argc) { - if (gen_extract(stdout, root, argv[optind])) - errx(1, "object not found: %s", argv[optind]); - optind++; - } + /* do what the user has requested */ + switch (op) { + + case OP_EXTRACT: + if (argc == 0) + errx(1, "-e requires arguments"); + + for (int i = 0; i < argc; i++) + if (gen_extract(stdout, root, argv[i])) + errx(1, "object not found: %s", argv[i]); return (0); - } - if (do_enums) { - make_enums(argc - optind, argv + optind, - gen_funcs_h, gen_funcs_c); + + case OP_ENUMS: + make_enums(argc, argv, gen_funcs); return (0); - } - if (do_tree) { + + case OP_TREE: + if (argc != 0) + errx(1, "-t allows no arguments"); gen_tree(root, 0); return (0); - } - sprintf(fname, "%stree.h", file_prefix); - if ((fp = fopen(fname, "w")) == NULL) - err(1, "%s: ", fname); - gen_header(fp, root, PREFIX_LEN, NULL); - fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n"); - extract_all_enums(fp, gen_funcs_h); - fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n"); - - fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); - fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); - - fclose(fp); - - sprintf(fname, "%stree.c", file_prefix); - if ((fp = fopen(fname, "w")) == NULL) - err(1, "%s: ", fname); - gen_table(fp, root); - fclose(fp); - - return (0); + case OP_GEN: + if (argc != 0) + errx(1, "tree generation allows no arguments"); + make_table(root, gen_funcs == GEN_FUNCS_H); + return (0); + } } Modified: head/contrib/bsnmp/lib/snmpclient.c ============================================================================== --- head/contrib/bsnmp/lib/snmpclient.c Tue Apr 2 12:02:35 2019 (r345796) +++ head/contrib/bsnmp/lib/snmpclient.c Tue Apr 2 12:50:01 2019 (r345797) @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2005 + * Copyright (c) 2004-2005,2018 * Hartmut Brandt. * All rights reserved. * Copyright (c) 2001-2003 @@ -34,11 +34,13 @@ * * Support functions for SNMP clients. */ -#include <sys/types.h> +#include <sys/param.h> #include <sys/time.h> #include <sys/queue.h> #include <sys/socket.h> #include <sys/un.h> +#include <net/if.h> +#include <ctype.h> #include <stdio.h> #include <stdlib.h> #include <stddef.h> @@ -58,12 +60,16 @@ #include <err.h> #endif +#include <arpa/inet.h> + #include "support.h" #include "asn1.h" #include "snmp.h" #include "snmpclient.h" #include "snmppriv.h" +#define DEBUG_PARSE 0 + /* global context */ struct snmp_client snmp_client; @@ -924,7 +930,8 @@ open_client_udp(const char *host, const char *port) /* open connection */ memset(&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; - hints.ai_family = AF_INET; + hints.ai_family = snmp_client.trans == SNMP_TRANS_UDP ? AF_INET: + AF_INET6; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = 0; error = getaddrinfo(snmp_client.chost, snmp_client.cport, &hints, &res0); @@ -1068,6 +1075,7 @@ snmp_open(const char *host, const char *port, const ch switch (snmp_client.trans) { case SNMP_TRANS_UDP: + case SNMP_TRANS_UDP6: if (open_client_udp(host, port) != 0) return (-1); break; @@ -1866,99 +1874,410 @@ snmp_client_set_port(struct snmp_client *cl, const cha return (0); } -/* - * parse a server specification +/** + * Try to get a transport identifier which is a leading alphanumeric string + * (starting with '_' or a letter and including also '_') terminated by + * a double colon. The string may not be empty. The transport identifier + * is optional. * - * [trans::][community@][server][:port] + * \param sc client struct to set errors + * \param strp possible start of transport; updated to point to + * the next character to parse + * + * \return end of transport; equals *strp if there is none; NULL if there + * was an error */ -int -snmp_parse_server(struct snmp_client *sc, const char *str) +static inline const char * +get_transp(struct snmp_client *sc, const char **strp) { - const char *p, *s = str; + const char *p = *strp; - /* look for a double colon */ - for (p = s; *p != '\0'; p++) { - if (*p == '\\' && p[1] != '\0') { + if (isascii(*p) && (isalpha(*p) || *p == '_')) { + p++; + while (isascii(*p) && (isalnum(*p) || *p == '_')) p++; - continue; + if (p[0] == ':' && p[1] == ':') { + *strp = p + 2; + return (p); } - if (*p == ':' && p[1] == ':') - break; } - if (*p != '\0') { - if (p > s) { - if (p - s == 3 && strncmp(s, "udp", 3) == 0) - sc->trans = SNMP_TRANS_UDP; - else if (p - s == 6 && strncmp(s, "stream", 6) == 0) - sc->trans = SNMP_TRANS_LOC_STREAM; - else if (p - s == 5 && strncmp(s, "dgram", 5) == 0) - sc->trans = SNMP_TRANS_LOC_DGRAM; - else { - seterr(sc, "unknown SNMP transport '%.*s'", - (int)(p - s), s); - return (-1); - } - } - s = p + 2; + if (p[0] == ':' && p[1] == ':') { + seterr(sc, "empty transport specifier"); + return (NULL); } + return (*strp); +} - /* look for a @ */ - for (p = s; *p != '\0'; p++) { - if (*p == '\\' && p[1] != '\0') { - p++; - continue; - } - if (*p == '@') - break; +/** + * Try to get community string. Eat everything up to the last @ (if there is + * any) but only if it is not longer than SNMP_COMMUNITY_MAXLEN. Empty + * community strings are legal. + * + * \param sc client struct to set errors + * \param strp possible start of community; updated to the point to + * the next character to parse + * + * \return end of community; equals *strp if there is none; NULL if there + * was an error + */ +static inline const char * +get_comm(struct snmp_client *sc, const char **strp) +{ + const char *p = strrchr(*strp, '@'); + + if (p == NULL) + /* no community string */ + return (*strp); + + if (p - *strp > SNMP_COMMUNITY_MAXLEN) { + seterr(sc, "community string too long '%.*s'", + p - *strp, *strp); + return (NULL); } - if (*p != '\0') { - if (p - s > SNMP_COMMUNITY_MAXLEN) { - seterr(sc, "community string too long"); - return (-1); + *strp = p + 1; + return (p); +} + +/** + * Try to get an IPv6 address. This starts with an [ and should end with an ] + * and everything between should be not longer than INET6_ADDRSTRLEN and + * parseable by inet_pton(). + * + * \param sc client struct to set errors + * \param strp possible start of IPv6 address (the '['); updated to point to + * the next character to parse (the one after the closing ']') + * + * \return end of address (equals *strp + 1 if there is none) or NULL + * on errors + */ +static inline const char * +get_ipv6(struct snmp_client *sc, const char **strp) +{ + char str[INET6_ADDRSTRLEN + IF_NAMESIZE]; + struct addrinfo hints, *res; + int error; + + if (**strp != '[') + return (*strp + 1); + + const char *p = *strp + 1; + while (*p != ']' ) { + if (*p == '\0') { + seterr(sc, "unterminated IPv6 address '%.*s'", + p - *strp, *strp); + return (NULL); } - strncpy(sc->read_community, s, p - s); - sc->read_community[p - s] = '\0'; - strncpy(sc->write_community, s, p - s); - sc->write_community[p - s] = '\0'; - s = p + 1; + p++; } - /* look for a colon */ - for (p = s; *p != '\0'; p++) { - if (*p == '\\' && p[1] != '\0') { - p++; - continue; - } - if (*p == ':') - break; + if (p - *strp > INET6_ADDRSTRLEN + IF_NAMESIZE) { + seterr(sc, "IPv6 address too long '%.*s'", p - *strp, *strp); + return (NULL); } - if (*p == ':') { - if (p > s) { - /* host:port */ - free(sc->chost); - if ((sc->chost = malloc(p - s + 1)) == NULL) { - seterr(sc, "%s", strerror(errno)); - return (-1); - } - strncpy(sc->chost, s, p - s); - sc->chost[p - s] = '\0'; + strncpy(str, *strp + 1, p - (*strp + 1)); + str[p - (*strp + 1)] = '\0'; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME | AI_NUMERICHOST; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + error = getaddrinfo(str, NULL, &hints, &res); + if (error != 0) { + seterr(sc, "%s: %s", str, gai_strerror(error)); + return (NULL); + } + freeaddrinfo(res); + *strp = p + 1; + return (p); +} + +/** + * Try to get an IPv4 address. This starts with a digit and consists of digits + * and dots, is not longer INET_ADDRSTRLEN and must be parseable by + * inet_aton(). + * + * \param sc client struct to set errors + * \param strp possible start of IPv4 address; updated to point to the + * next character to parse + * + * \return end of address (equals *strp if there is none) or NULL + * on errors + */ +static inline const char * +get_ipv4(struct snmp_client *sc, const char **strp) +{ + const char *p = *strp; + + while (isascii(*p) && (isdigit(*p) || *p == '.')) + p++; + + if (p - *strp > INET_ADDRSTRLEN) { + seterr(sc, "IPv4 address too long '%.*s'", p - *strp, *strp); + return (NULL); + } + if (*strp == p) + return *strp; + + char str[INET_ADDRSTRLEN + 1]; + strncpy(str, *strp, p - *strp); + str[p - *strp] = '\0'; + + struct in_addr addr; + if (inet_aton(str, &addr) != 1) { + seterr(sc, "illegal IPv4 address '%s'", str); + return (NULL); + } + + *strp = p; + return (p); +} + +/** + * Try to get a hostname. This includes everything up to but not including + * the last colon (if any). There is no length restriction. + * + * \param sc client struct to set errors + * \param strp possible start of hostname; updated to point to the next + * character to parse (the trailing NUL character or the last + * colon) + * + * \return end of address (equals *strp if there is none) + */ +static inline const char * +get_host(struct snmp_client *sc __unused, const char **strp) +{ + const char *p = strrchr(*strp, ':'); + + if (p == NULL) { + *strp += strlen(*strp); + return (*strp); + } + + *strp = p; + return (p); +} + +/** + * Try to get a port number. This start with a colon and extends to the end + * of string. The port number must not be empty. + * + * \param sc client struct to set errors *** DIFF OUTPUT TRUNCATED AT 1000 LINES *** _______________________________________________ svn-src-head@freebsd.org mailing list https://lists.freebsd.org/mailman/listinfo/svn-src-head To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"