📄 routerparse.c
字号:
/* Copyright (c) 2001 Matej Pfajfar.
* Copyright (c) 2001-2004, Roger Dingledine.
* Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
* Copyright (c) 2007-2008, The Tor Project, Inc. */
/* See LICENSE for licensing information */
/* $Id$ */
const char routerparse_c_id[] =
"$Id$";
/**
* \file routerparse.c
* \brief Code to parse and validate router descriptors and directories.
**/
#include "or.h"
#include "memarea.h"
/****************************************************************************/
/** Enumeration of possible token types. The ones starting with K_ correspond
* to directory 'keywords'. _ERR is an error in the tokenizing process, _EOF
* is an end-of-file marker, and _NIL is used to encode not-a-token.
*/
typedef enum {
K_ACCEPT = 0,
K_DIRECTORY_SIGNATURE,
K_RECOMMENDED_SOFTWARE,
K_REJECT,
K_ROUTER,
K_SIGNED_DIRECTORY,
K_SIGNING_KEY,
K_ONION_KEY,
K_ROUTER_SIGNATURE,
K_PUBLISHED,
K_RUNNING_ROUTERS,
K_ROUTER_STATUS,
K_PLATFORM,
K_OPT,
K_BANDWIDTH,
K_PORTS,
K_CONTACT,
K_NETWORK_STATUS,
K_UPTIME,
K_DIR_SIGNING_KEY,
K_FAMILY,
K_FINGERPRINT,
K_HIBERNATING,
K_READ_HISTORY,
K_WRITE_HISTORY,
K_NETWORK_STATUS_VERSION,
K_DIR_SOURCE,
K_DIR_OPTIONS,
K_CLIENT_VERSIONS,
K_SERVER_VERSIONS,
K_R,
K_S,
K_V,
K_EVENTDNS,
K_EXTRA_INFO,
K_EXTRA_INFO_DIGEST,
K_CACHES_EXTRA_INFO,
K_HIDDEN_SERVICE_DIR,
K_DIR_KEY_CERTIFICATE_VERSION,
K_DIR_IDENTITY_KEY,
K_DIR_KEY_PUBLISHED,
K_DIR_KEY_EXPIRES,
K_DIR_KEY_CERTIFICATION,
K_DIR_ADDRESS,
K_VOTE_STATUS,
K_VALID_AFTER,
K_FRESH_UNTIL,
K_VALID_UNTIL,
K_VOTING_DELAY,
K_KNOWN_FLAGS,
K_VOTE_DIGEST,
K_CONSENSUS_DIGEST,
K_CONSENSUS_METHODS,
K_CONSENSUS_METHOD,
A_PURPOSE,
_A_UNKNOWN,
R_RENDEZVOUS_SERVICE_DESCRIPTOR,
R_VERSION,
R_PERMANENT_KEY,
R_SECRET_ID_PART,
R_PUBLICATION_TIME,
R_PROTOCOL_VERSIONS,
R_INTRODUCTION_POINTS,
R_SIGNATURE,
R_IPO_IDENTIFIER,
R_IPO_IP_ADDRESS,
R_IPO_ONION_PORT,
R_IPO_ONION_KEY,
R_IPO_SERVICE_KEY,
_UNRECOGNIZED,
_ERR,
_EOF,
_NIL
} directory_keyword;
#define MIN_ANNOTATION A_PURPOSE
#define MAX_ANNOTATION _A_UNKNOWN
/** Structure to hold a single directory token.
*
* We parse a directory by breaking it into "tokens", each consisting
* of a keyword, a line full of arguments, and a binary object. The
* arguments and object are both optional, depending on the keyword
* type.
*
* This structure is only allocated in memareas; do not allocate it on
* the heap, or token_free() won't work.
*/
typedef struct directory_token_t {
directory_keyword tp; /**< Type of the token. */
int n_args:30; /**< Number of elements in args */
char **args; /**< Array of arguments from keyword line. */
char *object_type; /**< -----BEGIN [object_type]-----*/
size_t object_size; /**< Bytes in object_body */
char *object_body; /**< Contents of object, base64-decoded. */
crypto_pk_env_t *key; /**< For public keys only. Heap-allocated. */
char *error; /**< For _ERR tokens only. */
} directory_token_t;
/* ********************************************************************** */
/** We use a table of rules to decide how to parse each token type. */
/** Rules for whether the keyword needs an object. */
typedef enum {
NO_OBJ, /**< No object, ever. */
NEED_OBJ, /**< Object is required. */
NEED_KEY_1024, /**< Object is required, and must be a 1024 bit public key */
NEED_KEY, /**< Object is required, and must be a public key. */
OBJ_OK, /**< Object is optional. */
} obj_syntax;
#define AT_START 1
#define AT_END 2
/** Determines the parsing rules for a single token type. */
typedef struct token_rule_t {
/** The string value of the keyword identifying the type of item. */
const char *t;
/** The corresponding directory_keyword enum. */
directory_keyword v;
/** Minimum number of arguments for this item */
int min_args;
/** Maximum number of arguments for this item */
int max_args;
/** If true, we concatenate all arguments for this item into a single
* string. */
int concat_args;
/** Requirments on object syntax for this item. */
obj_syntax os;
/** Lowest number of times this item may appear in a document. */
int min_cnt;
/** Highest number of times this item may appear in a document. */
int max_cnt;
/** One or more of AT_START/AT_END to limit where the item may appear in a
* document. */
int pos;
/** True iff this token is an annotation. */
int is_annotation;
} token_rule_t;
/*
* Helper macros to define token tables. 's' is a string, 't' is a
* directory_keyword, 'a' is a trio of argument multiplicities, and 'o' is an
* object syntax.
*
*/
/** Appears to indicate the end of a table. */
#define END_OF_TABLE { NULL, _NIL, 0,0,0, NO_OBJ, 0, INT_MAX, 0, 0 }
/** An item with no restrictions: used for obsolete document types */
#define T(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
/** An item with no restrictions on multiplicity or location. */
#define T0N(s,t,a,o) { s, t, a, o, 0, INT_MAX, 0, 0 }
/** An item that must appear exactly once */
#define T1(s,t,a,o) { s, t, a, o, 1, 1, 0, 0 }
/** An item that must appear exactly once, at the start of the document */
#define T1_START(s,t,a,o) { s, t, a, o, 1, 1, AT_START, 0 }
/** An item that must appear exactly once, at the end of the document */
#define T1_END(s,t,a,o) { s, t, a, o, 1, 1, AT_END, 0 }
/** An item that must appear one or more times */
#define T1N(s,t,a,o) { s, t, a, o, 1, INT_MAX, 0, 0 }
/** An item that must appear no more than once */
#define T01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 }
/** An annotation that must appear no more than once */
#define A01(s,t,a,o) { s, t, a, o, 0, 1, 0, 0 }
/* Argument multiplicity: any number of arguments. */
#define ARGS 0,INT_MAX,0
/* Argument multiplicity: no arguments. */
#define NO_ARGS 0,0,0
/* Argument multiplicity: concatenate all arguments. */
#define CONCAT_ARGS 1,1,1
/* Argument multiplicity: at least <b>n</b> arguments. */
#define GE(n) n,INT_MAX,0
/* Argument multiplicity: exactly <b>n</b> arguments. */
#define EQ(n) n,n,0
/** List of tokens allowable in router derscriptors */
static token_rule_t routerdesc_token_table[] = {
T0N("reject", K_REJECT, ARGS, NO_OBJ ),
T0N("accept", K_ACCEPT, ARGS, NO_OBJ ),
T1_START( "router", K_ROUTER, GE(5), NO_OBJ ),
T1( "signing-key", K_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
T1( "onion-key", K_ONION_KEY, NO_ARGS, NEED_KEY_1024 ),
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T01("uptime", K_UPTIME, GE(1), NO_OBJ ),
T01("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
T01("hibernating", K_HIBERNATING, GE(1), NO_OBJ ),
T01("platform", K_PLATFORM, CONCAT_ARGS, NO_OBJ ),
T01("contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
T01("extra-info-digest", K_EXTRA_INFO_DIGEST, GE(1), NO_OBJ ),
T01("hidden-service-dir", K_HIDDEN_SERVICE_DIR, NO_ARGS, NO_OBJ ),
T01("family", K_FAMILY, ARGS, NO_OBJ ),
T01("caches-extra-info", K_CACHES_EXTRA_INFO, NO_ARGS, NO_OBJ ),
T01("eventdns", K_EVENTDNS, ARGS, NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T1( "bandwidth", K_BANDWIDTH, GE(3), NO_OBJ ),
A01("@purpose", A_PURPOSE, GE(1), NO_OBJ ),
END_OF_TABLE
};
/** List of tokens allowable in extra-info documents. */
static token_rule_t extrainfo_token_table[] = {
T1_END( "router-signature", K_ROUTER_SIGNATURE, NO_ARGS, NEED_OBJ ),
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T01("read-history", K_READ_HISTORY, ARGS, NO_OBJ ),
T01("write-history", K_WRITE_HISTORY, ARGS, NO_OBJ ),
T1_START( "extra-info", K_EXTRA_INFO, GE(2), NO_OBJ ),
END_OF_TABLE
};
/** List of tokens allowable in the body part of v2 and v3 networkstatus
* documents. */
static token_rule_t rtrstatus_token_table[] = {
T1( "r", K_R, GE(8), NO_OBJ ),
T1( "s", K_S, ARGS, NO_OBJ ),
T01("v", K_V, CONCAT_ARGS, NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
END_OF_TABLE
};
/** List of tokens allowable in the header part of v2 networkstatus documents.
*/
static token_rule_t netstatus_token_table[] = {
T1( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
T1( "dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY_1024 ),
T1( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
T1_START("network-status-version", K_NETWORK_STATUS_VERSION,
GE(1), NO_OBJ ),
T1( "dir-source", K_DIR_SOURCE, GE(3), NO_OBJ ),
T01("dir-options", K_DIR_OPTIONS, ARGS, NO_OBJ ),
T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
/** List of tokens allowable in the footer of v1/v2 directory/networkstatus
* footers. */
static token_rule_t dir_footer_token_table[] = {
T1("directory-signature", K_DIRECTORY_SIGNATURE, EQ(1), NEED_OBJ ),
END_OF_TABLE
};
/** List of tokens allowable in v1 directory headers/footers. */
static token_rule_t dir_token_table[] = {
/* don't enforce counts; this is obsolete. */
T( "network-status", K_NETWORK_STATUS, NO_ARGS, NO_OBJ ),
T( "directory-signature", K_DIRECTORY_SIGNATURE, ARGS, NEED_OBJ ),
T( "recommended-software",K_RECOMMENDED_SOFTWARE,CONCAT_ARGS, NO_OBJ ),
T( "signed-directory", K_SIGNED_DIRECTORY, NO_ARGS, NO_OBJ ),
T( "running-routers", K_RUNNING_ROUTERS, ARGS, NO_OBJ ),
T( "router-status", K_ROUTER_STATUS, ARGS, NO_OBJ ),
T( "published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T( "opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
T( "dir-signing-key", K_DIR_SIGNING_KEY, ARGS, OBJ_OK ),
T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
#define CERTIFICATE_MEMBERS \
T1("dir-key-certificate-version", K_DIR_KEY_CERTIFICATE_VERSION, \
GE(1), NO_OBJ ), \
T1("dir-identity-key", K_DIR_IDENTITY_KEY, NO_ARGS, NEED_KEY ),\
T1("dir-key-published",K_DIR_KEY_PUBLISHED, CONCAT_ARGS, NO_OBJ), \
T1("dir-key-expires", K_DIR_KEY_EXPIRES, CONCAT_ARGS, NO_OBJ), \
T1("dir-signing-key", K_DIR_SIGNING_KEY, NO_ARGS, NEED_KEY ),\
T1("dir-key-certification", K_DIR_KEY_CERTIFICATION, \
NO_ARGS, NEED_OBJ), \
T01("dir-address", K_DIR_ADDRESS, GE(1), NO_OBJ),
static token_rule_t dir_key_certificate_table[] = {
CERTIFICATE_MEMBERS
T1("fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
END_OF_TABLE
};
/** List of tokens allowable in rendezvous service descriptors */
static token_rule_t desc_token_table[] = {
T1_START("rendezvous-service-descriptor", R_RENDEZVOUS_SERVICE_DESCRIPTOR,
EQ(1), NO_OBJ),
T1("version", R_VERSION, EQ(1), NO_OBJ),
T1("permanent-key", R_PERMANENT_KEY, NO_ARGS, NEED_KEY_1024),
T1("secret-id-part", R_SECRET_ID_PART, EQ(1), NO_OBJ),
T1("publication-time", R_PUBLICATION_TIME, CONCAT_ARGS, NO_OBJ),
T1("protocol-versions", R_PROTOCOL_VERSIONS, EQ(1), NO_OBJ),
T01("introduction-points", R_INTRODUCTION_POINTS, NO_ARGS, NEED_OBJ),
T1_END("signature", R_SIGNATURE, NO_ARGS, NEED_OBJ),
END_OF_TABLE
};
/** List of tokens allowed in the (encrypted) list of introduction points of
* rendezvous service descriptors */
static token_rule_t ipo_token_table[] = {
T1_START("introduction-point", R_IPO_IDENTIFIER, EQ(1), NO_OBJ),
T1("ip-address", R_IPO_IP_ADDRESS, EQ(1), NO_OBJ),
T1("onion-port", R_IPO_ONION_PORT, EQ(1), NO_OBJ),
T1("onion-key", R_IPO_ONION_KEY, NO_ARGS, NEED_KEY_1024),
T1("service-key", R_IPO_SERVICE_KEY, NO_ARGS, NEED_KEY_1024),
END_OF_TABLE
};
static token_rule_t networkstatus_token_table[] = {
T1("network-status-version", K_NETWORK_STATUS_VERSION,
GE(1), NO_OBJ ),
T1("vote-status", K_VOTE_STATUS, GE(1), NO_OBJ ),
T1("published", K_PUBLISHED, CONCAT_ARGS, NO_OBJ ),
T1("valid-after", K_VALID_AFTER, CONCAT_ARGS, NO_OBJ ),
T1("fresh-until", K_FRESH_UNTIL, CONCAT_ARGS, NO_OBJ ),
T1("valid-until", K_VALID_UNTIL, CONCAT_ARGS, NO_OBJ ),
T1("voting-delay", K_VOTING_DELAY, GE(2), NO_OBJ ),
T1("known-flags", K_KNOWN_FLAGS, ARGS, NO_OBJ ),
T( "fingerprint", K_FINGERPRINT, CONCAT_ARGS, NO_OBJ ),
CERTIFICATE_MEMBERS
T0N("opt", K_OPT, CONCAT_ARGS, OBJ_OK ),
T1( "contact", K_CONTACT, CONCAT_ARGS, NO_OBJ ),
T1( "dir-source", K_DIR_SOURCE, GE(6), NO_OBJ ),
T1( "known-flags", K_KNOWN_FLAGS, CONCAT_ARGS, NO_OBJ ),
T01("client-versions", K_CLIENT_VERSIONS, CONCAT_ARGS, NO_OBJ ),
T01("server-versions", K_SERVER_VERSIONS, CONCAT_ARGS, NO_OBJ ),
T1( "consensus-methods", K_CONSENSUS_METHODS, GE(1), NO_OBJ ),
END_OF_TABLE
};
static token_rule_t networkstatus_consensus_token_table[] = {
T1("network-status-version", K_NETWORK_STATUS_VERSION,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -