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
This commit is contained in:
Andrey V. Elsukov 2019-04-02 12:50:01 +00:00
parent a8cb655d2e
commit 04d1781439
18 changed files with 2278 additions and 298 deletions

View File

@ -31,7 +31,7 @@
.\" .\"
.\" $Begemot: gensnmptree.1 383 2006-05-30 07:40:49Z brandt_h $ .\" $Begemot: gensnmptree.1 383 2006-05-30 07:40:49Z brandt_h $
.\" .\"
.Dd June 29, 2018 .Dd April 2, 2019
.Dt GENSNMPTREE 1 .Dt GENSNMPTREE 1
.Os .Os
.Sh NAME .Sh NAME
@ -100,25 +100,11 @@ is the length of the OID.
is the last component of the OID. is the last component of the OID.
.El .El
.It Fl F .It Fl F
Together with emit definitions for C-functions includeable in a C-file that do some basic
.Fl E stuff on enums like value checking and conversion between value and strings.
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.
.It Fl f .It Fl f
This flag can be used together with emit definitions for inline C-functions that do some basic
.Fl E stuff on enums like value checking and conversion between value and strings.
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.
.It Fl h .It Fl h
Print a short help page. Print a short help page.
.It Fl I Ar directory .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 Prefix the file names and the table name with
.Ar prefix . .Ar prefix .
.El .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 .Sh MIBS
The syntax of the MIB description file can formally be specified as follows: The syntax of the MIB description file can formally be specified as follows:
.Bd -unfilled -offset indent .Bd -unfilled -offset indent

View File

@ -110,7 +110,6 @@ static int debug;
static const char usgtxt[] = "\ static const char usgtxt[] = "\
Generate SNMP tables.\n\ Generate SNMP tables.\n\
$Id$\n\
usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\ usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\
[name]...\n\ [name]...\n\
options:\n\ options:\n\
@ -127,6 +126,37 @@ options:\n\
-t generate a .def file\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 * A node in the OID tree
*/ */
@ -162,15 +192,18 @@ struct node {
uint32_t index; /* index for table entry */ uint32_t index; /* index for table entry */
char *func; /* function for tables */ char *func; /* function for tables */
struct node_list subs; struct node_list subs;
char *subtypes[SNMP_INDEXES_MAX];
} entry; } entry;
struct leaf { struct leaf {
enum snmp_syntax syntax; /* syntax for this leaf */ enum snmp_syntax syntax; /* syntax for this leaf */
char *func; /* function name */ char *func; /* function name */
char *subtype; /* subtype */
} leaf; } leaf;
struct column { struct column {
enum snmp_syntax syntax; /* syntax for this column */ enum snmp_syntax syntax; /* syntax for this column */
char *subtype; /* subtype */
} column; } column;
} u; } u;
}; };
@ -214,7 +247,7 @@ xalloc(size_t size)
{ {
void *ptr; void *ptr;
if ((ptr = malloc(size)) == NULL) if ((ptr = calloc(1, size)) == NULL)
err(1, "allocing %zu bytes", size); err(1, "allocing %zu bytes", size);
return (ptr); return (ptr);
@ -710,12 +743,14 @@ make_type(const char *s)
* token. * token.
*/ */
static u_int 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; u_int syntax;
struct enums *e; struct enums *e;
syntax = val; syntax = val;
if (subtype != NULL)
*subtype = NULL;
if (*tok == TOK_ENUM || *tok == TOK_BITS) { if (*tok == TOK_ENUM || *tok == TOK_BITS) {
if (t == NULL && vname != NULL) { if (t == NULL && vname != NULL) {
@ -759,6 +794,8 @@ parse_type(enum tok *tok, struct type *t, const char *vname)
if ((*tok = gettoken()) == '|') { if ((*tok = gettoken()) == '|') {
if (gettoken() != TOK_STR) if (gettoken() != TOK_STR)
report("subtype expected after '|'"); report("subtype expected after '|'");
if (subtype != NULL)
*subtype = savetok();
*tok = gettoken(); *tok = gettoken();
} }
} }
@ -794,18 +831,21 @@ parse(enum tok tok)
if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE || if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE ||
tok == TOK_ENUM || tok == TOK_BITS) { tok == TOK_ENUM || tok == TOK_BITS) {
/* LEAF or COLUM */ /* 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) { if (tok == TOK_STR) {
/* LEAF */ /* LEAF */
node->type = NODE_LEAF; node->type = NODE_LEAF;
node->u.leaf.func = savetok(); node->u.leaf.func = savetok();
node->u.leaf.syntax = syntax; node->u.leaf.syntax = syntax;
node->u.leaf.subtype = subtype;
tok = gettoken(); tok = gettoken();
} else { } else {
/* COLUMN */ /* COLUMN */
node->type = NODE_COLUMN; node->type = NODE_COLUMN;
node->u.column.syntax = syntax; node->u.column.syntax = syntax;
node->u.column.subtype = subtype;
} }
while (tok != ')') { while (tok != ')') {
@ -825,9 +865,12 @@ parse(enum tok tok)
tok = gettoken(); tok = gettoken();
while (tok == TOK_TYPE || tok == TOK_DEFTYPE || while (tok == TOK_TYPE || tok == TOK_DEFTYPE ||
tok == TOK_ENUM || tok == TOK_BITS) { tok == TOK_ENUM || tok == TOK_BITS) {
u_int syntax = parse_type(&tok, NULL, node->name); char *subtype;
if (index_count++ == SNMP_INDEXES_MAX) u_int syntax = parse_type(&tok, NULL, node->name,
&subtype);
if (index_count == SNMP_INDEXES_MAX)
report("too many table indexes"); report("too many table indexes");
node->u.entry.subtypes[index_count++] = subtype;
node->u.entry.index |= node->u.entry.index |=
syntax << (SNMP_INDEX_SHIFT * index_count); syntax << (SNMP_INDEX_SHIFT * index_count);
} }
@ -882,7 +925,8 @@ parse_top(enum tok tok)
tok = gettoken(); tok = gettoken();
t->is_enum = (tok == TOK_ENUM); t->is_enum = (tok == TOK_ENUM);
t->is_bits = (tok == TOK_BITS); t->is_bits = (tok == TOK_BITS);
t->syntax = parse_type(&tok, t, NULL);
t->syntax = parse_type(&tok, t, NULL, NULL);
pushback(tok); pushback(tok);
return (NULL); return (NULL);
@ -903,7 +947,7 @@ parse_top(enum tok tok)
* Generate the C-code table part for one node. * Generate the C-code table part for one node.
*/ */
static void 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) const char *func)
{ {
u_int n; u_int n;
@ -1008,7 +1052,7 @@ gen_node(FILE *fp, struct node *np, struct asn_oid *oid, u_int idx,
* Generate the header file with the function declarations. * Generate the header file with the function declarations.
*/ */
static void 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]; char f[MAXSTR + 4];
struct node *sub; struct node *sub;
@ -1058,7 +1102,7 @@ gen_header(FILE *fp, struct node *np, u_int oidlen, const char *func)
* Generate the OID table. * Generate the OID table.
*/ */
static void static void
gen_table(FILE *fp, struct node *node) gen_table(FILE *fp, const struct node *node)
{ {
struct asn_oid oid; struct asn_oid oid;
@ -1067,7 +1111,6 @@ gen_table(FILE *fp, struct node *node)
#ifdef HAVE_STDINT_H #ifdef HAVE_STDINT_H
fprintf(fp, "#include <stdint.h>\n"); fprintf(fp, "#include <stdint.h>\n");
#endif #endif
fprintf(fp, "#include <string.h>\n");
if (localincs) { if (localincs) {
fprintf(fp, "#include \"asn1.h\"\n"); fprintf(fp, "#include \"asn1.h\"\n");
fprintf(fp, "#include \"snmp.h\"\n"); fprintf(fp, "#include \"snmp.h\"\n");
@ -1118,6 +1161,8 @@ gen_tree(const struct node *np, int level)
case NODE_LEAF: case NODE_LEAF:
print_syntax(np->u.leaf.syntax); 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, printf(" %s%s%s)\n", np->u.leaf.func,
(np->flags & FL_GET) ? " GET" : "", (np->flags & FL_GET) ? " GET" : "",
(np->flags & FL_SET) ? " SET" : ""); (np->flags & FL_SET) ? " SET" : "");
@ -1137,8 +1182,11 @@ gen_tree(const struct node *np, int level)
case NODE_ENTRY: case NODE_ENTRY:
printf(" :"); 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)); 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); printf(" %s\n", np->u.entry.func);
TAILQ_FOREACH(sp, &np->u.entry.subs, link) TAILQ_FOREACH(sp, &np->u.entry.subs, link)
gen_tree(sp, level + 1); gen_tree(sp, level + 1);
@ -1147,6 +1195,8 @@ gen_tree(const struct node *np, int level)
case NODE_COLUMN: case NODE_COLUMN:
print_syntax(np->u.column.syntax); 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" : "", printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
(np->flags & FL_SET) ? " SET" : ""); (np->flags & FL_SET) ? " SET" : "");
break; break;
@ -1194,15 +1244,6 @@ extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj,
return (1); 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 static int
gen_extract(FILE *fp, const struct node *root, char *object) gen_extract(FILE *fp, const struct node *root, char *object)
{ {
@ -1390,45 +1431,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. * Generate helper functions for an enum.
* *
@ -1493,6 +1495,54 @@ gen_enum_funcs(FILE *fp, const struct type *t, int ccode)
fprintf(fp, "}\n"); fprintf(fp, "}\n");
} }
/**
* 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. * Generate helper functions for an enum. This generates code for a c file.
* *
@ -1529,6 +1579,16 @@ gen_all_enum_funcs(FILE *fp, int ccode)
gen_enum_funcs(fp, t, 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 * Extract a given enum to the specified file and optionally generate static
* inline helper functions for them. * inline helper functions for them.
@ -1546,9 +1606,7 @@ extract_enum(FILE *fp, const char *name, int gen_funcs)
LIST_FOREACH(t, &types, link) LIST_FOREACH(t, &types, link)
if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
gen_enum(fp, t); gen_enum(fp, t, gen_funcs);
if (gen_funcs)
gen_enum_funcs(fp, t, 0);
return (0); return (0);
} }
return (-1); return (-1);
@ -1567,11 +1625,8 @@ extract_all_enums(FILE *fp, int gen_funcs)
const struct type *t; const struct type *t;
LIST_FOREACH(t, &types, link) LIST_FOREACH(t, &types, link)
if (t->is_enum || t->is_bits) { if (t->is_enum || t->is_bits)
gen_enum(fp, t); gen_enum(fp, t, gen_funcs);
if (gen_funcs)
gen_enum_funcs(fp, t, 0);
}
} }
/** /**
@ -1579,13 +1634,12 @@ extract_all_enums(FILE *fp, int gen_funcs)
* *
* \param argc number of arguments * \param argc number of arguments
* \param argv arguments (enum names) * \param argv arguments (enum names)
* \param gen_funcs_h generate functions into the header file * \param gen_funcs which functions to generate
* \param gen_funcs_c generate a .c file with functions
*/ */
static void 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) if (argc == 0)
gen_all_enum_funcs(stdout, 1); gen_all_enum_funcs(stdout, 1);
else { else {
@ -1595,30 +1649,58 @@ make_enums(int argc, char *argv[], int gen_funcs_h, int gen_funcs_c)
} }
} else { } else {
if (argc == 0) if (argc == 0)
extract_all_enums(stdout, gen_funcs_h); extract_all_enums(stdout, gen_funcs == GEN_FUNCS_H);
else { else {
for (int i = 0; i < argc; i++) 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]); 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 int
main(int argc, char *argv[]) main(int argc, char *argv[])
{ {
int do_extract = 0; enum op op = OP_GEN;
int do_tree = 0; enum gen_funcs gen_funcs = GEN_FUNCS_NONE;
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;
char *infile = NULL; char *infile = NULL;
int opt;
while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF) while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF)
switch (opt) { switch (opt) {
@ -1627,19 +1709,29 @@ main(int argc, char *argv[])
break; break;
case 'E': case 'E':
do_enums = 1; if (op != OP_GEN && op != OP_ENUMS)
errx(1, "-E conflicts with earlier options");
op = OP_ENUMS;
break; break;
case 'e': case 'e':
do_extract = 1; if (op != OP_GEN && op != OP_EXTRACT)
errx(1, "-e conflicts with earlier options");
op = OP_EXTRACT;
break; break;
case 'F': 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; break;
case 'f': 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; break;
case 'h': case 'h':
@ -1666,75 +1758,61 @@ main(int argc, char *argv[])
break; break;
case 't': case 't':
do_tree = 1; if (op != OP_GEN && op != OP_TREE)
errx(1, "-t conflicts with earlier options");
op = OP_TREE;
break; break;
} }
if (do_extract + do_tree + do_enums > 1) argc -= optind;
errx(1, "conflicting options -e/-t/-E"); argv += optind;
if (!do_extract && !do_enums && argc != optind)
errx(1, "no arguments allowed");
if (do_extract && argc == optind)
errx(1, "no objects specified");
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) { if (infile == NULL) {
input_new(stdin, NULL, "<stdin>"); input_new(stdin, NULL, "<stdin>");
} else { } else {
FILE *fp;
if ((fp = fopen(infile, "r")) == NULL) if ((fp = fopen(infile, "r")) == NULL)
err(1, "%s", infile); err(1, "%s", infile);
input_new(fp, NULL, 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) while ((tok = gettoken()) != TOK_EOF)
merge(&root, parse_top(tok)); merge(&root, parse_top(tok));
if (root) if (root)
check_tree(root); check_tree(root);
if (do_extract) { /* do what the user has requested */
while (optind < argc) { switch (op) {
if (gen_extract(stdout, root, argv[optind]))
errx(1, "object not found: %s", argv[optind]); case OP_EXTRACT:
optind++; 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); return (0);
}
if (do_enums) { case OP_ENUMS:
make_enums(argc - optind, argv + optind, make_enums(argc, argv, gen_funcs);
gen_funcs_h, gen_funcs_c);
return (0); return (0);
}
if (do_tree) { case OP_TREE:
if (argc != 0)
errx(1, "-t allows no arguments");
gen_tree(root, 0); gen_tree(root, 0);
return (0); 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);
} }
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);
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2004-2005 * Copyright (c) 2004-2005,2018
* Hartmut Brandt. * Hartmut Brandt.
* All rights reserved. * All rights reserved.
* Copyright (c) 2001-2003 * Copyright (c) 2001-2003
@ -34,11 +34,13 @@
* *
* Support functions for SNMP clients. * Support functions for SNMP clients.
*/ */
#include <sys/types.h> #include <sys/param.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/queue.h> #include <sys/queue.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/un.h> #include <sys/un.h>
#include <net/if.h>
#include <ctype.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <stddef.h> #include <stddef.h>
@ -58,12 +60,16 @@
#include <err.h> #include <err.h>
#endif #endif
#include <arpa/inet.h>
#include "support.h" #include "support.h"
#include "asn1.h" #include "asn1.h"
#include "snmp.h" #include "snmp.h"
#include "snmpclient.h" #include "snmpclient.h"
#include "snmppriv.h" #include "snmppriv.h"
#define DEBUG_PARSE 0
/* global context */ /* global context */
struct snmp_client snmp_client; struct snmp_client snmp_client;
@ -924,7 +930,8 @@ open_client_udp(const char *host, const char *port)
/* open connection */ /* open connection */
memset(&hints, 0, sizeof(hints)); memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_CANONNAME; 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_socktype = SOCK_DGRAM;
hints.ai_protocol = 0; hints.ai_protocol = 0;
error = getaddrinfo(snmp_client.chost, snmp_client.cport, &hints, &res0); error = getaddrinfo(snmp_client.chost, snmp_client.cport, &hints, &res0);
@ -1068,6 +1075,7 @@ snmp_open(const char *host, const char *port, const char *readcomm,
switch (snmp_client.trans) { switch (snmp_client.trans) {
case SNMP_TRANS_UDP: case SNMP_TRANS_UDP:
case SNMP_TRANS_UDP6:
if (open_client_udp(host, port) != 0) if (open_client_udp(host, port) != 0)
return (-1); return (-1);
break; break;
@ -1866,99 +1874,410 @@ snmp_client_set_port(struct snmp_client *cl, const char *p)
return (0); 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
*/
static inline const char *
get_transp(struct snmp_client *sc, const char **strp)
{
const char *p = *strp;
if (isascii(*p) && (isalpha(*p) || *p == '_')) {
p++;
while (isascii(*p) && (isalnum(*p) || *p == '_'))
p++;
if (p[0] == ':' && p[1] == ':') {
*strp = p + 2;
return (p);
}
}
if (p[0] == ':' && p[1] == ':') {
seterr(sc, "empty transport specifier");
return (NULL);
}
return (*strp);
}
/**
* 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);
}
*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);
}
p++;
}
if (p - *strp > INET6_ADDRSTRLEN + IF_NAMESIZE) {
seterr(sc, "IPv6 address too long '%.*s'", p - *strp, *strp);
return (NULL);
}
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
* \param strp possible start of port specification; if this points to a
* colon there is a port specification
*
* \return end of port number (equals *strp if there is none); NULL
* if there is no port number
*/
static inline const char *
get_port(struct snmp_client *sc, const char **strp)
{
if (**strp != ':')
return (*strp + 1);
if ((*strp)[1] == '\0') {
seterr(sc, "empty port name");
return (NULL);
}
*strp += strlen(*strp);
return (*strp);
}
/**
* Save the string in the range given by two pointers.
*
* \param sc client struct to set errors
* \param s begin and end pointers
*
* \return freshly allocated copy of the string between s[0] and s[1]
*/
static inline char *
save_str(struct snmp_client *sc, const char *const s[2])
{
char *m;
if ((m = malloc(s[1] - s[0] + 1)) == NULL) {
seterr(sc, "%s: %s", __func__, strerror(errno));
return (NULL);
}
strncpy(m, s[0], s[1] - s[0]);
m[s[1] - s[0]] = '\0';
return (m);
}
/**
* Parse a server specification. All parts are optional:
*
* [<trans>::][<comm>@][<host-or-ip>][:<port>]
*
* The transport string consists of letters, digits or '_' and starts with
* a letter or digit. It is terminated by two colons and may not be empty.
*
* The community string is terminated by the last '@' and does not exceed
* SNMP_COMMUNITY_MAXLEN. It may be empty.
*
* The host or ip is either an IPv4 address (as parsed by inet_pton()), an
* IPv6 address in '[' and ']' and parseable by inet_aton() or a hostname
* terminated by the last colon or by the NUL character.
*
* The port number may be specified numerically or symbolically and starts
* with the last colon.
*
* The functions sets the chost, cport, trans, read_community and
* write_community fields on success and the error field on errors.
* The chost and cport fields are allocated by malloc(3), their previous
* content is deallocated by free(3).
*
* The function explicitly allows mismatches between the transport and
* the address type in order to support IPv4 in IPv6 addresses.
*
* \param sc client struct to fill
* \param str string to parse
*
* \return 0 on success and -1 on errors
*/ */
int int
snmp_parse_server(struct snmp_client *sc, const char *str) snmp_parse_server(struct snmp_client *sc, const char *str)
{ {
const char *p, *s = str; #if DEBUG_PARSE
const char *const orig = str;
#endif
/* look for a double colon */ const char *const trans_list[] = {
for (p = s; *p != '\0'; p++) { [SNMP_TRANS_UDP] = "udp",
if (*p == '\\' && p[1] != '\0') { [SNMP_TRANS_LOC_DGRAM] = "dgram",
p++; [SNMP_TRANS_LOC_STREAM] = "stream",
continue; [SNMP_TRANS_UDP6] = "udp6",
} };
if (*p == ':' && p[1] == ':')
break; /* parse input */
} const char *const transp[2] = {
if (*p != '\0') { str,
if (p > s) { get_transp(sc, &str),
if (p - s == 3 && strncmp(s, "udp", 3) == 0) };
sc->trans = SNMP_TRANS_UDP; if (transp[1] == NULL)
else if (p - s == 6 && strncmp(s, "stream", 6) == 0) return (-1);
sc->trans = SNMP_TRANS_LOC_STREAM;
else if (p - s == 5 && strncmp(s, "dgram", 5) == 0) const char *const comm[2] = {
sc->trans = SNMP_TRANS_LOC_DGRAM; str,
else { get_comm(sc, &str),
seterr(sc, "unknown SNMP transport '%.*s'", };
(int)(p - s), s); if (comm[1] == NULL)
return (-1); return (-1);
}
} const char *const ipv6[2] = {
s = p + 2; str + 1,
get_ipv6(sc, &str),
};
if (ipv6[1] == NULL)
return (-1);
const char *ipv4[2] = {
str,
str,
};
const char *host[2] = {
str,
str,
};
if (ipv6[0] == ipv6[1]) {
ipv4[1] = get_ipv4(sc, &str);
if (ipv4[0] == ipv4[1])
host[1] = get_host(sc, &str);
} }
/* look for a @ */ const char *port[2] = {
for (p = s; *p != '\0'; p++) { str + 1,
if (*p == '\\' && p[1] != '\0') { get_port(sc, &str),
p++; };
continue; if (port[1] == NULL)
} return (-1);
if (*p == '@')
break; if (*str != '\0') {
seterr(sc, "junk at end of server specification '%s'", str);
return (-1);
} }
if (*p != '\0') { #if DEBUG_PARSE
if (p - s > SNMP_COMMUNITY_MAXLEN) { printf("transp: %zu %zu\n", transp[0] - orig, transp[1] - orig);
seterr(sc, "community string too long"); printf("comm: %zu %zu\n", comm[0] - orig, comm[1] - orig);
return (-1); printf("ipv6: %zu %zu\n", ipv6[0] - orig, ipv6[1] - orig);
} printf("ipv4: %zu %zu\n", ipv4[0] - orig, ipv4[1] - orig);
strncpy(sc->read_community, s, p - s); printf("host: %zu %zu\n", host[0] - orig, host[1] - orig);
sc->read_community[p - s] = '\0'; printf("port: %zu %zu\n", port[0] - orig, port[1] - orig);
strncpy(sc->write_community, s, p - s); #endif
sc->write_community[p - s] = '\0';
s = p + 1;
}
/* look for a colon */ /* analyse and allocate */
for (p = s; *p != '\0'; p++) { int i = -1;
if (*p == '\\' && p[1] != '\0') { if (transp[0] != transp[1]) {
p++; for (i = 0; i < (int)nitems(trans_list); i++) {
continue; if (trans_list[i] != NULL &&
} strlen(trans_list[i]) == (size_t)(transp[1] -
if (*p == ':') transp[0]) && !strncmp(trans_list[i], transp[0],
break; transp[1] - transp[0]))
} break;
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';
}
/* port */
free(sc->cport);
if ((sc->cport = strdup(p + 1)) == NULL) {
seterr(sc, "%s", strerror(errno));
return (-1);
} }
} else if (p > s) { if (i == (int)nitems(trans_list)) {
/* host */ seterr(sc, "unknown transport specifier '%.*s'",
free(sc->chost); transp[1] - transp[0], transp[0]);
if ((sc->chost = strdup(s)) == NULL) {
seterr(sc, "%s", strerror(errno));
return (-1); return (-1);
} }
} }
char *chost;
if (ipv6[0] != ipv6[1]) {
if ((chost = save_str(sc, ipv6)) == NULL)
return (-1);
if (i == -1)
i = SNMP_TRANS_UDP6;
} else if (ipv4[0] != ipv4[1]) {
if ((chost = save_str(sc, ipv4)) == NULL)
return (-1);
if (i == -1)
i = SNMP_TRANS_UDP;
} else {
if ((chost = save_str(sc, host)) == NULL)
return (-1);
if (i == -1) {
/* Default transport is UDP unless the host contains
* a slash in which case we default to DGRAM. */
i = SNMP_TRANS_UDP;
for (const char *p = host[0]; p < host[1]; p++)
if (*p == '/') {
i = SNMP_TRANS_LOC_DGRAM;
break;
}
}
}
char *cport = save_str(sc, port);
if (cport == NULL) {
free(chost);
return (-1);
}
/* commit */
sc->trans = i;
strncpy(sc->read_community, comm[0], comm[1] - comm[0]);
sc->read_community[comm[1] - comm[0]] = '\0';
strncpy(sc->write_community, comm[0], comm[1] - comm[0]);
sc->write_community[comm[1] - comm[0]] = '\0';
free(sc->chost);
sc->chost = chost;
free(sc->cport);
sc->cport = cport;
return (0); return (0);
} }

View File

@ -49,6 +49,7 @@
#define SNMP_TRANS_UDP 0 #define SNMP_TRANS_UDP 0
#define SNMP_TRANS_LOC_DGRAM 1 #define SNMP_TRANS_LOC_DGRAM 1
#define SNMP_TRANS_LOC_STREAM 2 #define SNMP_TRANS_LOC_STREAM 2
#define SNMP_TRANS_UDP6 3
/* type of callback function for responses /* type of callback function for responses
* this callback function is responsible for free() any memory associated with * this callback function is responsible for free() any memory associated with

View File

@ -46,3 +46,11 @@ typedef StorageType ENUM (
5 readOnly 5 readOnly
) )
typedef InetAddressType ENUM (
0 unknown
1 ipv4
2 ipv6
3 ipv4z
4 ipv6z
16 dns
)

View File

@ -3,6 +3,10 @@
-- Fraunhofer Institute for Open Communication Systems (FhG Fokus). -- Fraunhofer Institute for Open Communication Systems (FhG Fokus).
-- All rights reserved. -- All rights reserved.
-- --
-- Copyright (c) 2018
-- Hartmut Brandt.
-- All rights reserved.
--
-- Author: Harti Brandt <harti@freebsd.org> -- Author: Harti Brandt <harti@freebsd.org>
-- --
-- Redistribution and use in source and binary forms, with or without -- Redistribution and use in source and binary forms, with or without
@ -34,17 +38,17 @@ BEGEMOT-SNMPD-MIB DEFINITIONS ::= BEGIN
IMPORTS IMPORTS
MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY, Counter32, MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY, Counter32,
Unsigned32, IpAddress Integer32, Unsigned32, IpAddress
FROM SNMPv2-SMI FROM SNMPv2-SMI
TEXTUAL-CONVENTION, TruthValue, RowStatus TEXTUAL-CONVENTION, TruthValue, RowStatus
FROM SNMPv2-TC FROM SNMPv2-TC
MODULE-COMPLIANCE, OBJECT-GROUP InetAddressType, InetAddress, InetPortNumber
FROM SNMPv2-CONF FROM INET-ADDRESS-MIB
begemot begemot
FROM BEGEMOT-MIB; FROM BEGEMOT-MIB;
begemotSnmpd MODULE-IDENTITY begemotSnmpd MODULE-IDENTITY
LAST-UPDATED "201801190000Z" LAST-UPDATED "201808080000Z"
ORGANIZATION "Fraunhofer FOKUS, CATS" ORGANIZATION "Fraunhofer FOKUS, CATS"
CONTACT-INFO CONTACT-INFO
" Hartmut Brandt " Hartmut Brandt
@ -59,6 +63,9 @@ begemotSnmpd MODULE-IDENTITY
E-mail: harti@freebsd.org" E-mail: harti@freebsd.org"
DESCRIPTION DESCRIPTION
"The MIB module for the Begemot SNMP daemon." "The MIB module for the Begemot SNMP daemon."
REVISION "201808080000Z"
DESCRIPTION
"Add the begemotSnmpdTransInetTable."
::= { begemot 1 } ::= { begemot 1 }
begemotSnmpdObjects OBJECT IDENTIFIER ::= { begemotSnmpd 1 } begemotSnmpdObjects OBJECT IDENTIFIER ::= { begemotSnmpd 1 }
@ -93,7 +100,7 @@ begemotSnmpdAgentFreeBSD OBJECT-IDENTITY
begemotSnmpdConfig OBJECT IDENTIFIER ::= { begemotSnmpdObjects 1 } begemotSnmpdConfig OBJECT IDENTIFIER ::= { begemotSnmpdObjects 1 }
begemotSnmpdTransmitBuffer OBJECT-TYPE begemotSnmpdTransmitBuffer OBJECT-TYPE
SYNTAX INTEGER (484..65535) SYNTAX Integer32 (484..65535)
MAX-ACCESS read-write MAX-ACCESS read-write
STATUS current STATUS current
DESCRIPTION DESCRIPTION
@ -103,7 +110,7 @@ begemotSnmpdTransmitBuffer OBJECT-TYPE
::= { begemotSnmpdConfig 1 } ::= { begemotSnmpdConfig 1 }
begemotSnmpdReceiveBuffer OBJECT-TYPE begemotSnmpdReceiveBuffer OBJECT-TYPE
SYNTAX INTEGER (484..65535) SYNTAX Integer32 (484..65535)
MAX-ACCESS read-write MAX-ACCESS read-write
STATUS current STATUS current
DESCRIPTION DESCRIPTION
@ -181,7 +188,7 @@ begemotTrapSinkAddr OBJECT-TYPE
::= { begemotTrapSinkEntry 1 } ::= { begemotTrapSinkEntry 1 }
begemotTrapSinkPort OBJECT-TYPE begemotTrapSinkPort OBJECT-TYPE
SYNTAX INTEGER (1..65535) SYNTAX Integer32 (1..65535)
MAX-ACCESS not-accessible MAX-ACCESS not-accessible
STATUS current STATUS current
DESCRIPTION DESCRIPTION
@ -203,7 +210,7 @@ begemotTrapSinkStatus OBJECT-TYPE
begemotSnmpdPortTable OBJECT-TYPE begemotSnmpdPortTable OBJECT-TYPE
SYNTAX SEQUENCE OF BegemotSnmpdPortEntry SYNTAX SEQUENCE OF BegemotSnmpdPortEntry
MAX-ACCESS not-accessible MAX-ACCESS not-accessible
STATUS current STATUS deprecated
DESCRIPTION DESCRIPTION
"A table with descriptions of UDP ports to listen on "A table with descriptions of UDP ports to listen on
for SNMP messages." for SNMP messages."
@ -212,7 +219,7 @@ begemotSnmpdPortTable OBJECT-TYPE
begemotSnmpdPortEntry OBJECT-TYPE begemotSnmpdPortEntry OBJECT-TYPE
SYNTAX BegemotSnmpdPortEntry SYNTAX BegemotSnmpdPortEntry
MAX-ACCESS not-accessible MAX-ACCESS not-accessible
STATUS current STATUS deprecated
DESCRIPTION DESCRIPTION
"An entry in the table with descriptions of UDP ports to "An entry in the table with descriptions of UDP ports to
listen on for SNMP messages." listen on for SNMP messages."
@ -228,15 +235,15 @@ BegemotSnmpdPortEntry ::= SEQUENCE {
begemotSnmpdPortAddress OBJECT-TYPE begemotSnmpdPortAddress OBJECT-TYPE
SYNTAX IpAddress SYNTAX IpAddress
MAX-ACCESS not-accessible MAX-ACCESS not-accessible
STATUS current STATUS deprecated
DESCRIPTION DESCRIPTION
"The IP address to bind to." "The IP address to bind to."
::= { begemotSnmpdPortEntry 1 } ::= { begemotSnmpdPortEntry 1 }
begemotSnmpdPortPort OBJECT-TYPE begemotSnmpdPortPort OBJECT-TYPE
SYNTAX INTEGER (1..65535) SYNTAX Integer32 (1..65535)
MAX-ACCESS not-accessible MAX-ACCESS not-accessible
STATUS current STATUS deprecated
DESCRIPTION DESCRIPTION
"The UDP port to listen on for SNMP messages." "The UDP port to listen on for SNMP messages."
::= { begemotSnmpdPortEntry 2 } ::= { begemotSnmpdPortEntry 2 }
@ -244,7 +251,7 @@ begemotSnmpdPortPort OBJECT-TYPE
begemotSnmpdPortStatus OBJECT-TYPE begemotSnmpdPortStatus OBJECT-TYPE
SYNTAX INTEGER { valid(1), invalid(2) } SYNTAX INTEGER { valid(1), invalid(2) }
MAX-ACCESS read-create MAX-ACCESS read-create
STATUS current STATUS deprecated
DESCRIPTION DESCRIPTION
"Set status to 1 to create entry, set it to 2 to delete it." "Set status to 1 to create entry, set it to 2 to delete it."
::= { begemotSnmpdPortEntry 3 } ::= { begemotSnmpdPortEntry 3 }
@ -275,7 +282,7 @@ BegemotSnmpdCommunityEntry ::= SEQUENCE {
begemotSnmpdCommunityIndex Unsigned32, begemotSnmpdCommunityIndex Unsigned32,
begemotSnmpdCommunityString OCTET STRING, begemotSnmpdCommunityString OCTET STRING,
begemotSnmpdCommunityDescr OCTET STRING, begemotSnmpdCommunityDescr OCTET STRING,
begemotSnmpdCommunityPermission INTEGER begemotSnmpdCommunityPermission Unsigned32
} }
begemotSnmpdCommunityModule OBJECT-TYPE begemotSnmpdCommunityModule OBJECT-TYPE
@ -312,7 +319,7 @@ begemotSnmpdCommunityDescr OBJECT-TYPE
::= { begemotSnmpdCommunityEntry 4 } ::= { begemotSnmpdCommunityEntry 4 }
begemotSnmpdCommunityPermission OBJECT-TYPE begemotSnmpdCommunityPermission OBJECT-TYPE
SYNTAX INTEGER (1..4294967295) SYNTAX Unsigned32 (1..4294967295)
MAX-ACCESS not-accessible MAX-ACCESS not-accessible
STATUS current STATUS current
DESCRIPTION DESCRIPTION
@ -449,7 +456,7 @@ begemotSnmpdDebugSnmpTrace OBJECT-TYPE
::= { begemotSnmpdDebug 2 } ::= { begemotSnmpdDebug 2 }
begemotSnmpdDebugSyslogPri OBJECT-TYPE begemotSnmpdDebugSyslogPri OBJECT-TYPE
SYNTAX INTEGER (0..8) SYNTAX Integer32 (0..8)
MAX-ACCESS read-write MAX-ACCESS read-write
STATUS current STATUS current
DESCRIPTION DESCRIPTION
@ -570,10 +577,115 @@ begemotSnmpdTransportOid OBJECT-TYPE
"A pointer to the group with the transport-dependend stuff." "A pointer to the group with the transport-dependend stuff."
::= { begemotSnmpdTransportEntry 3 } ::= { begemotSnmpdTransportEntry 3 }
-- ----------------------------------------------------------------------
--
-- Internet port table.
--
BegemotSnmpdTransportProto ::= TEXTUAL-CONVENTION
STATUS current
DESCRIPTION
"A value that represents the type of protocol to be used for
listening on a socket. The following protocols are currently
used:
udp(1) Use UDP for IPv4 and IPv6 sockets."
SYNTAX INTEGER {
udp(1)
}
begemotSnmpdTransInetTable OBJECT-TYPE
SYNTAX SEQUENCE OF BegemotSnmpdTransInetEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"This table contains all the ports the daemon should listen on.
Entries can be created at initialization time via the config
file or at run time via a SET. One row can map to several open
sockets in the case of InetAddressType::dns rows. These rows
open one socket for each address returned by getaddrinfo(3).
for SNMP messages."
::= { begemotSnmpdObjects 11 }
begemotSnmpdTransInetEntry OBJECT-TYPE
SYNTAX BegemotSnmpdTransInetEntry
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"A row of the internet port table. Each row may map to one or
more listening sockets."
INDEX {
begemotSnmpdTransInetAddressType,
begemotSnmpdTransInetAddress,
begemotSnmpdTransInetPort,
begemotSnmpdTransInetProto
}
::= { begemotSnmpdTransInetTable 1 }
BegemotSnmpdTransInetEntry ::= SEQUENCE {
begemotSnmpdTransInetAddressType InetAddressType,
begemotSnmpdTransInetAddress InetAddress,
begemotSnmpdTransInetPort InetPortNumber,
begemotSnmpdTransInetProto BegemotSnmpdTransportProto,
begemotSnmpdTransInetStatus RowStatus
}
begemotSnmpdTransInetAddressType OBJECT-TYPE
SYNTAX InetAddressType
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"The type of the address. Only ipv4, ipv6, ipv6z and dns are
supported."
::= { begemotSnmpdTransInetEntry 1 }
begemotSnmpdTransInetAddress OBJECT-TYPE
SYNTAX InetAddress (SIZE (0..64))
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"The address. For ipv4 addresses the length must be 4, ipv6
addresses have a length of 16 and ipv6z addresses a length of
20 where the last four bytes are the interface index in big
endian format. dns addresses may be of zero-length in which case
getaddrinfo() generates INADDR_ANY and its IPv6 equivalent. dns
addresses will open a socket for all addresses returned by
getaddrinfo()."
::= { begemotSnmpdTransInetEntry 2 }
begemotSnmpdTransInetPort OBJECT-TYPE
SYNTAX InetPortNumber (1..65535)
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"The port to listen on for SNMP messages."
::= { begemotSnmpdTransInetEntry 3 }
begemotSnmpdTransInetProto OBJECT-TYPE
SYNTAX BegemotSnmpdTransportProto
MAX-ACCESS not-accessible
STATUS current
DESCRIPTION
"The protocol to use. Currently only the value udp(1) is supported."
::= { begemotSnmpdTransInetEntry 4 }
begemotSnmpdTransInetStatus OBJECT-TYPE
SYNTAX RowStatus
MAX-ACCESS read-create
STATUS current
DESCRIPTION
"The status of the conceptual row. A row may be created using
createAndGo(4) or createAndWait(5). An inactive row can be
activated writing active(1) and an active row can be inactivated
by writing notInService(2). Finally active or inactive rows can be
deleted by writing the value destroy(6). The value of this field
will never read as notReady(3)."
::= { begemotSnmpdTransInetEntry 5 }
-- --
-- XXX These should go into their own MIB -- XXX These should go into their own MIB
-- --
begemotSnmpdTransUdp OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 2 } begemotSnmpdTransUdp OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 2 }
begemotSnmpdTransLsock OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 3 } begemotSnmpdTransLsock OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 3 }
begemotSnmpdTransInet OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 4 }
END END

View File

@ -65,6 +65,8 @@
#include "tree.h" #include "tree.h"
#include "oid.h" #include "oid.h"
#include "trans_inet.h"
#define PATH_PID "/var/run/%s.pid" #define PATH_PID "/var/run/%s.pid"
#define PATH_CONFIG "/etc/%s.config" #define PATH_CONFIG "/etc/%s.config"
#define PATH_ENGINE "/var/%s.engine" #define PATH_ENGINE "/var/%s.engine"
@ -1038,7 +1040,7 @@ snmpd_input(struct port_input *pi, struct tport *tport)
ssize_t ret, slen; ssize_t ret, slen;
int32_t vi; int32_t vi;
#ifdef USE_TCPWRAPPERS #ifdef USE_TCPWRAPPERS
char client[16]; char client[INET6_ADDRSTRLEN];
#endif #endif
ret = tport->transport->vtab->recv(tport, pi); ret = tport->transport->vtab->recv(tport, pi);
@ -1184,8 +1186,12 @@ snmpd_input(struct port_input *pi, struct tport *tport)
sndbuf, &sndlen, "SNMP", ierr, vi, NULL); sndbuf, &sndlen, "SNMP", ierr, vi, NULL);
if (ferr == SNMPD_INPUT_OK) { if (ferr == SNMPD_INPUT_OK) {
slen = tport->transport->vtab->send(tport, sndbuf, sndlen, if (tport->transport->vtab->send != NULL)
pi->peer, pi->peerlen); slen = tport->transport->vtab->send(tport, sndbuf,
sndlen, pi->peer, pi->peerlen);
else
slen = tport->transport->vtab->send2(tport, sndbuf,
sndlen, pi);
if (slen == -1) if (slen == -1)
syslog(LOG_ERR, "send*: %m"); syslog(LOG_ERR, "send*: %m");
else if ((size_t)slen != sndlen) else if ((size_t)slen != sndlen)
@ -1201,7 +1207,8 @@ snmpd_input(struct port_input *pi, struct tport *tport)
} }
/* /*
* Send a PDU to a given port * Send a PDU to a given port. If this is a multi-socket port, use the
* first socket.
*/ */
void void
snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
@ -1224,7 +1231,10 @@ snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY");
len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); if (trans->vtab->send != NULL)
len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen);
else
len = trans->vtab->send2(tp, sndbuf, sndlen, NULL);
if (len == -1) if (len == -1)
syslog(LOG_ERR, "sendto: %m"); syslog(LOG_ERR, "sendto: %m");
@ -1238,16 +1248,37 @@ snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu,
/* /*
* Close an input source * Close an input source
*
* \param pi input instance
*/ */
void void
snmpd_input_close(struct port_input *pi) snmpd_input_close(struct port_input *pi)
{ {
if (pi->id != NULL) if (pi->id != NULL) {
fd_deselect(pi->id); fd_deselect(pi->id);
if (pi->fd >= 0) pi->id = NULL;
}
if (pi->fd >= 0) {
(void)close(pi->fd); (void)close(pi->fd);
if (pi->buf != NULL) pi->fd = -1;
}
if (pi->buf != NULL) {
free(pi->buf); free(pi->buf);
pi->buf = NULL;
}
}
/*
* Initialize an input source.
*
* \param pi input instance
*/
void
snmpd_input_init(struct port_input *pi)
{
pi->id = NULL;
pi->fd = -1;
pi->buf = NULL;
} }
/* /*
@ -1633,6 +1664,8 @@ main(int argc, char *argv[])
syslog(LOG_WARNING, "cannot start UDP transport"); syslog(LOG_WARNING, "cannot start UDP transport");
if (lsock_trans.start() != SNMP_ERR_NOERROR) if (lsock_trans.start() != SNMP_ERR_NOERROR)
syslog(LOG_WARNING, "cannot start LSOCK transport"); syslog(LOG_WARNING, "cannot start LSOCK transport");
if (inet_trans.start() != SNMP_ERR_NOERROR)
syslog(LOG_WARNING, "cannot start INET transport");
#ifdef USE_LIBBEGEMOT #ifdef USE_LIBBEGEMOT
if (debug.evdebug > 0) if (debug.evdebug > 0)

View File

@ -72,8 +72,18 @@ begemotSnmpdCommunityString.0.1 = $(read)
begemotSnmpdCommunityDisable = 1 begemotSnmpdCommunityDisable = 1
# open standard SNMP ports # open standard SNMP ports
begemotSnmpdPortStatus.[$(host)].161 = 1 # begemotSnmpdPortStatus.[$(host)].161 = 1
begemotSnmpdPortStatus.127.0.0.1.161 = 1 # begemotSnmpdPortStatus.127.0.0.1.161 = 1
# UDP over IPv4: 127.0.0.1:161
begemotSnmpdTransInetStatus.1.4.127.0.0.1.161.1 = 4
# UDP over IPv6: ::1:161
begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.161.1 = 4
# Use domain name and IPv6 link-local address with scope zone id as address
# begemotSnmpdTransInetStatus.16."localhost".161.1 = 4
# begemotSnmpdTransInetStatus.16."fe80::1%em0".161.1 = 4
# open a unix domain socket # open a unix domain socket
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1 begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1

View File

@ -174,7 +174,7 @@ TAILQ_HEAD(tport_list, tport);
int snmpd_input(struct port_input *, struct tport *); int snmpd_input(struct port_input *, struct tport *);
void snmpd_input_close(struct port_input *); void snmpd_input_close(struct port_input *);
void snmpd_input_init(struct port_input *);
/* /*
* Transport domain * Transport domain
@ -194,6 +194,10 @@ struct transport_def {
ssize_t (*send)(struct tport *, const u_char *, size_t, ssize_t (*send)(struct tport *, const u_char *, size_t,
const struct sockaddr *, size_t); const struct sockaddr *, size_t);
ssize_t (*recv)(struct tport *, struct port_input *); ssize_t (*recv)(struct tport *, struct port_input *);
/** send via a multi-socket port */
ssize_t (*send2)(struct tport *, const u_char *, size_t,
struct port_input *);
}; };
struct transport { struct transport {
struct asn_oid index; /* transport table index */ struct asn_oid index; /* transport table index */

View File

@ -56,6 +56,48 @@
* ordering can be done either on an integer/unsigned field, an asn_oid * ordering can be done either on an integer/unsigned field, an asn_oid
* or an ordering function. * or an ordering function.
*/ */
/*
* First set of macros is used when the link is embedded into sub-struct
* and links these sub-structs. The sub-struct must be the first field.
*
* The list is a list of the subfield types.
*/
#define INSERT_OBJECT_OID_LINK_INDEX_TYPE(PTR, LIST, LINK, INDEX, SUBF) do {\
typedef __typeof ((PTR)->SUBF) _subf_type; \
_subf_type *_lelem; \
\
TAILQ_FOREACH(_lelem, (LIST), LINK) \
if (asn_compare_oid(&_lelem->INDEX, &(PTR)->SUBF.INDEX) > 0)\
break; \
if (_lelem == NULL) \
TAILQ_INSERT_TAIL((LIST), &(PTR)->SUBF, LINK); \
else \
TAILQ_INSERT_BEFORE(_lelem, &(PTR)->SUBF, LINK); \
} while (0)
#define NEXT_OBJECT_OID_LINK_INDEX_TYPE(LIST, OID, SUB, LINK, INDEX, TYPE) ({\
__typeof (TAILQ_FIRST((LIST))) _lelem; \
\
TAILQ_FOREACH(_lelem, (LIST), LINK) \
if (index_compare(OID, SUB, &_lelem->INDEX) < 0) \
break; \
(TYPE *)(_lelem); \
})
#define FIND_OBJECT_OID_LINK_INDEX_TYPE(LIST, OID, SUB, LINK, INDEX, TYPE) ({\
__typeof (TAILQ_FIRST((LIST))) _lelem; \
\
TAILQ_FOREACH(_lelem, (LIST), LINK) \
if (index_compare(OID, SUB, &_lelem->INDEX) == 0) \
break; \
(TYPE *)(_lelem); \
})
/*
* This set of macros allows specification of the link and index name.
* The index is an OID.
*/
#define INSERT_OBJECT_OID_LINK_INDEX(PTR, LIST, LINK, INDEX) do { \ #define INSERT_OBJECT_OID_LINK_INDEX(PTR, LIST, LINK, INDEX) do { \
__typeof (PTR) _lelem; \ __typeof (PTR) _lelem; \
\ \

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2018
* Hartmut Brandt.
* All rights reserved.
*
* Author: Harti Brandt <harti@freebsd.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id$
*/
#ifndef trans_inet_h_1530971397
#define trans_inet_h_1530971397
/* transport declaration */
extern const struct transport_def inet_trans;
#endif

View File

@ -70,7 +70,8 @@ const struct transport_def lsock_trans = {
lsock_close_port, lsock_close_port,
lsock_init_port, lsock_init_port,
lsock_send, lsock_send,
lsock_recv lsock_recv,
NULL
}; };
static struct transport *my_trans; static struct transport *my_trans;

View File

@ -67,7 +67,8 @@ const struct transport_def udp_trans = {
udp_close_port, udp_close_port,
udp_init_port, udp_init_port,
udp_send, udp_send,
udp_recv udp_recv,
NULL
}; };
static struct transport *my_trans; static struct transport *my_trans;

View File

@ -3,6 +3,10 @@
# Fraunhofer Institute for Open Communication Systems (FhG Fokus). # Fraunhofer Institute for Open Communication Systems (FhG Fokus).
# All rights reserved. # All rights reserved.
# #
# Copyright (c) 2018
# Hartmut Brandt.
# All rights reserved.
#
# Author: Harti Brandt <harti@freebsd.org> # Author: Harti Brandt <harti@freebsd.org>
# #
# Redistribution and use in source and binary forms, with or without # Redistribution and use in source and binary forms, with or without
@ -33,6 +37,10 @@
include "tc.def" include "tc.def"
typedef BegemotSnmpdTransportProto ENUM (
1 udp
)
(1 internet (1 internet
(2 mgmt (2 mgmt
(1 mibII (1 mibII
@ -172,13 +180,24 @@ include "tc.def"
)) ))
(2 begemotSnmpdTransUdp OID op_transport_dummy) (2 begemotSnmpdTransUdp OID op_transport_dummy)
(3 begemotSnmpdTransLsock OID op_transport_dummy) (3 begemotSnmpdTransLsock OID op_transport_dummy)
(4 begemotSnmpdTransInet OID op_transport_dummy)
) )
(11 begemotSnmpdTransInetTable
(1 begemotSnmpdTransInetEntry : INTEGER OCTETSTRING INTEGER INTEGER op_snmp_trans_inet
(1 begemotSnmpdTransInetAddressType InetAddressType)
(2 begemotSnmpdTransInetAddress OCTETSTRING)
(3 begemotSnmpdTransInetPort INTEGER)
(4 begemotSnmpdTransInetProto BegemotSnmpdTransportProto)
(5 begemotSnmpdTransInetStatus RowStatus GET SET)
))
) )
(2 begemotSnmpdDefs (2 begemotSnmpdDefs
(1 begemotSnmpdAgent (1 begemotSnmpdAgent
(1 begemotSnmpdAgentFreeBSD OID op_dummy) (1 begemotSnmpdAgentFreeBSD OID op_dummy)
) )
) )
(3 begemotSnmpdCompliance)
) )
)) ))
) )

View File

@ -129,4 +129,8 @@ MLINKS+= bsnmplib.3 snmp_value_copy.3
MLINKS+= bsnmplib.3 snmp_value_free.3 MLINKS+= bsnmplib.3 snmp_value_free.3
MLINKS+= bsnmplib.3 snmp_value_parse.3 MLINKS+= bsnmplib.3 snmp_value_parse.3
FILESGROUPS+= DEFS
DEFS= tc.def
DEFSDIR?= ${SHAREDIR}/snmp/defs
.include <bsd.lib.mk> .include <bsd.lib.mk>

View File

@ -11,11 +11,11 @@ CONFS= snmpd.config
CONFSMODE= 600 CONFSMODE= 600
PROG= bsnmpd PROG= bsnmpd
SRCS= main.c action.c config.c export.c trap.c trans_udp.c trans_lsock.c SRCS= main.c action.c config.c export.c trap.c trans_udp.c trans_lsock.c
SRCS+= oid.h tree.c tree.h SRCS+= trans_inet.c oid.h tree.c tree.h
XSYM= snmpMIB begemotSnmpdModuleTable begemotSnmpd begemotTrapSinkTable \ XSYM= snmpMIB begemotSnmpdModuleTable begemotSnmpd begemotTrapSinkTable \
sysUpTime snmpTrapOID coldStart authenticationFailure \ sysUpTime snmpTrapOID coldStart authenticationFailure \
begemotSnmpdTransUdp begemotSnmpdTransLsock begemotSnmpdLocalPortTable \ begemotSnmpdTransUdp begemotSnmpdTransLsock begemotSnmpdLocalPortTable \
freeBSD freeBSDVersion freeBSD freeBSDVersion begemotSnmpdTransInet
CLEANFILES= oid.h tree.c tree.h CLEANFILES= oid.h tree.c tree.h
MAN= bsnmpd.1 snmpmod.3 MAN= bsnmpd.1 snmpmod.3

View File

@ -92,10 +92,22 @@ begemotSnmpdDebugSyslogPri = 7
# #
begemotSnmpdCommunityString.0.1 = $(read) begemotSnmpdCommunityString.0.1 = $(read)
# begemotSnmpdCommunityString.0.2 = $(write) # begemotSnmpdCommunityString.0.2 = $(write)
# begemotSnmpdCommunityString.0.3 = "otherPublic"
begemotSnmpdCommunityDisable = 1 begemotSnmpdCommunityDisable = 1
# open standard SNMP ports # open standard SNMP ports
begemotSnmpdPortStatus.0.0.0.0.161 = 1 begemotSnmpdTransInetStatus.1.4.0.0.0.0.161.1 = 4
begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.161.1 = 4
# UDP over IPv4: 127.0.0.1:161
# begemotSnmpdTransInetStatus.1.4.127.0.0.1.161.1 = 4
# UDP over IPv6: ::1:161
# begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.161.1 = 4
# Use domain name and IPv6 link-local address with scope zone id as address
# begemotSnmpdTransInetStatus.16."localhost".161.1 = 4
# begemotSnmpdTransInetStatus.16."fe80::1%em0".161.1 = 4
# open a unix domain socket # open a unix domain socket
begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1 begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1