diff options
Diffstat (limited to '')
-rw-r--r-- | nsock/src/nsock_internal.h | 522 |
1 files changed, 522 insertions, 0 deletions
diff --git a/nsock/src/nsock_internal.h b/nsock/src/nsock_internal.h new file mode 100644 index 0000000..dc47c3f --- /dev/null +++ b/nsock/src/nsock_internal.h @@ -0,0 +1,522 @@ +/*************************************************************************** + * nsock_internal.h -- PRIVATE interface definitions for the guts of the * + * nsock parallel socket event library. Applications calling this library * + * should NOT include this. even LOOK at these :). * + * * + ***********************IMPORTANT NSOCK LICENSE TERMS*********************** + * + * The nsock parallel socket event library is (C) 1999-2023 Nmap Software LLC + * This library is free software; you may redistribute and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; Version 2. This guarantees your right to use, modify, and + * redistribute this software under certain conditions. If this license is + * unacceptable to you, Nmap Software LLC may be willing to sell alternative + * licenses (contact sales@nmap.com ). + * + * As a special exception to the GPL terms, Nmap Software LLC grants permission + * to link the code of this program with any version of the OpenSSL library + * which is distributed under a license identical to that listed in the included + * docs/licenses/OpenSSL.txt file, and distribute linked combinations including + * the two. You must obey the GNU GPL in all respects for all of the code used + * other than OpenSSL. If you modify this file, you may extend this exception to + * your version of the file, but you are not obligated to do so. + * + * If you received these files with a written license agreement stating terms + * other than the (GPL) terms above, then that alternative license agreement + * takes precedence over this comment. + * + * Source is provided to this software because we believe users have a right to + * know exactly what a program is going to do before they run it. This also + * allows you to audit the software for security holes. + * + * Source code also allows you to port Nmap to new platforms, fix bugs, and add + * new features. You are highly encouraged to send your changes to the + * dev@nmap.org mailing list for possible incorporation into the main + * distribution. By sending these changes to Fyodor or one of the Insecure.Org + * development mailing lists, or checking them into the Nmap source code + * repository, it is understood (unless you specify otherwise) that you are + * offering the Nmap Project (Nmap Software LLC) the unlimited, non-exclusive + * right to reuse, modify, and relicense the code. Nmap will always be available + * Open Source, but this is important because the inability to relicense code + * has caused devastating problems for other Free Software projects (such as KDE + * and NASM). We also occasionally relicense the code to third parties as + * discussed above. If you wish to specify special license conditions of your + * contributions, just say so when you send them. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License v2.0 for more + * details (http://www.gnu.org/licenses/gpl-2.0.html). + * + ***************************************************************************/ + +/* $Id$ */ + +#ifndef NSOCK_INTERNAL_H +#define NSOCK_INTERNAL_H + +#include <nbase.h> + +#ifdef HAVE_CONFIG_H +#include "nsock_config.h" +#include "nbase_config.h" +#endif + +#ifdef WIN32 +#include "nbase_winconfig.h" +#include <Winsock2.h> +#endif + +#include "gh_list.h" +#include "gh_heap.h" +#include "filespace.h" +#include "nsock.h" /* The public interface -- I need it for some enum defs */ +#include "nsock_ssl.h" +#include "nsock_proxy.h" + +#if HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#if HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#if HAVE_STRING_H +#include <string.h> +#endif +#if HAVE_STRINGS_H +#include <strings.h> +#endif +#if HAVE_SYS_UN_H +#include <sys/un.h> +#endif + +#ifndef IPPROTO_SCTP +#define IPPROTO_SCTP 132 +#endif + + +/* ------------------- CONSTANTS ------------------- */ +#define READ_BUFFER_SZ 8192 + +enum nsock_read_types { + NSOCK_READLINES, + NSOCK_READBYTES, + NSOCK_READ +}; + +enum iod_state { + NSIOD_STATE_DELETED, + NSIOD_STATE_INITIAL, + + /* sd was provided to us in nsock_iod_new2 (see nsock_iod.c) */ + NSIOD_STATE_UNKNOWN, + + NSIOD_STATE_CONNECTED_TCP, + NSIOD_STATE_CONNECTED_UDP +}; + +/* XXX: ensure that these values can be OR'ed when adding new ones */ +#define EV_NONE 0x00 +#define EV_READ 0x01 +#define EV_WRITE 0x02 +#define EV_EXCEPT 0x04 + + +/* ------------------- STRUCTURES ------------------- */ + +struct readinfo { + enum nsock_read_types read_type; + /* num lines; num bytes; whatever (depends on read_type) */ + int num; +}; + +struct writeinfo { + struct sockaddr_storage dest; + size_t destlen; + /* Number of bytes successfully written */ + int written_so_far; +}; + +/* Remember that callers of this library should NOT be accessing these + * fields directly */ +struct npool { + /* User data, NULL if unset */ + void *userdata; + + /* IO Engine vtable */ + struct io_engine *engine; + /* IO Engine internal data */ + void *engine_data; + + /* Active network events */ + gh_list_t connect_events; + gh_list_t read_events; + gh_list_t write_events; +#if HAVE_PCAP + gh_list_t pcap_read_events; +#endif + gh_heap_t expirables; + + /* Active iods and related lists of events */ + gh_list_t active_iods; + + /* struct niod structures that have been freed for reuse */ + gh_list_t free_iods; + /* When an event is deleted, we stick it here for later reuse */ + gh_list_t free_events; + + /* Number of events pending (total) on all lists */ + int events_pending; + + /* Serial # of next event (used to create next nsock_event_id */ + unsigned long next_event_serial; + /* Serial # of next iod to be created */ + unsigned long next_iod_serial; + + /* If nsock_loop() returns NSOCK_LOOP_ERROR, this is where we describe the + * error (errnum fashion) */ + int errnum; + + /* If true, new sockets will have SO_BROADCAST set */ + int broadcast; + + /* Interface to bind to; only supported on Linux with SO_BINDTODEVICE sockopt. */ + const char *device; + + /* If true, exit the next iteration of nsock_loop with a status of + * NSOCK_LOOP_QUIT. */ + int quit; + +#if HAVE_OPENSSL + /* The SSL Context (options and such) */ + SSL_CTX *sslctx; +#ifdef HAVE_DTLS_CLIENT_METHOD + SSL_CTX *dtlsctx; +#endif +#endif + + /* Optional proxy chain (NULL is not set). Can only be set once per NSP (using + * nsock_proxychain_new() or nsock_pool_set_proxychain(). */ + struct proxy_chain *px_chain; + +}; + + +/* nsock_iod is like a "file descriptor" for the nsock library. You use it to + * request events. */ +struct niod { + /* The socket descriptor related to the event */ + int sd; + + /* Number of pending events on this iod */ + int events_pending; + + /* Pending events */ + gh_lnode_t *first_connect; + gh_lnode_t *first_read; + gh_lnode_t *first_write; +#if HAVE_PCAP + gh_lnode_t *first_pcap_read; +#endif + + int readsd_count; + int writesd_count; +#if HAVE_PCAP + int readpcapsd_count; +#endif + + int watched_events; + + /* The struct npool used to create the iod (used for deletion) */ + struct npool *nsp; + + enum iod_state state; + + /* The host and port we are connected to using sd (saves a call to getpeername) */ + struct sockaddr_storage peer; + /* The host and port to bind to with sd */ + struct sockaddr_storage local; + + /* The length of peer/local actually used (sizeof(sockaddr_in) or + * sizeof(sockaddr_in6), SUN_LEN(sockaddr_un), or 0 if peer/local + * has not been filled in */ + size_t locallen; + size_t peerlen; + + /* -1 if none yet, otherwise IPPROTO_TCP, etc. */ + int lastproto; + + /* The struct npool keeps track of NIODs that have been allocated so that it + * can destroy them if the msp is deleted. This pointer makes it easy to + * remove this struct niod from the allocated list when necessary */ + gh_lnode_t nodeq; + +#define IOD_REGISTERED 0x01 +#define IOD_PROCESSED 0x02 /* internally used by engine_kqueue.c */ + +#define IOD_PROPSET(iod, flag) ((iod)->_flags |= (flag)) +#define IOD_PROPCLR(iod, flag) ((iod)->_flags &= ~(flag)) +#define IOD_PROPGET(iod, flag) (((iod)->_flags & (flag)) != 0) + char _flags; + + /* Used for SSL Server Name Indication. */ + char *hostname; + +#if HAVE_OPENSSL + /* An SSL connection (or NULL if none) */ + SSL *ssl; + /* SSL SESSION ID (or NULL if none) */ + SSL_SESSION *ssl_session; +#else + /* Because there are many if (nsi->ssl) cases in the code */ + char *ssl; +#endif + /* Every iod has an id which is always unique for the same nspool (unless you + * create billions of them) */ + unsigned long id; + + /* No. of bytes read from the sd*/ + unsigned long read_count; + /* No. of bytes written to the sd */ + unsigned long write_count; + + void *userdata; + + /* IP options to set on socket before connect() */ + void *ipopts; + int ipoptslen; + + /* Pointer to mspcap struct (used only if pcap support is included) */ + void *pcap; + + struct proxy_chain_context *px_ctx; + +}; + + +/* nsock_event_t handles a single event. Its ID is generally returned when the + * event is created, and the event is included in callbacks */ +struct nevent { + /* Every event has an ID which is unique for a given nsock unless you blow + * through more than 500,000,000 events */ + nsock_event_id id; + + enum nse_type type; + enum nse_status status; + + /* For write events, this is the data to be written, for read events, this is + * what we will read into */ + struct filespace iobuf; + + /* The timeout of the event -- absolute time + * except that tv_sec == 0 means no timeout */ + struct timeval timeout; + + /* Info pertaining to READ requests */ + struct readinfo readinfo; + /* Info pertaining to WRITE requests */ + struct writeinfo writeinfo; + +#if HAVE_OPENSSL + struct sslinfo sslinfo; +#endif + + /* If we return a status of NSE_STATUS_ERROR, this must be set */ + int errnum; + + /* The nsock I/O descriptor related to event (if applicable) */ + struct niod *iod; + + /* The handler to call when event is complete */ + nsock_ev_handler handler; + + /* slot in the expirable binheap */ + gh_hnode_t expire; + + /* For some reasons (see nsock_pcap.c) we register pcap events as both read + * and pcap_read events when in PCAP_BSD_SELECT_HACK mode. We then need two + * gh_lnode_t handles. To make code simpler, we _always_ use _nodeq_pcap for + * pcap_read events and _nodeq_io for the other ones. + * When not in PCAP_BSD_SELECT_HACK mode we define both handles as members + * of an union to optimize memory footprint. */ + gh_lnode_t nodeq_io; + gh_lnode_t nodeq_pcap; + + /* Optional (NULL if unset) pointer to pass to the handler */ + void *userdata; + + /* If this event is all filled out and ready for immediate delivery, + * event_done is nonzero. Used when event is finished at unexpected time and + * we want to dispatch it later to avoid duplicating stat update code and all + * that other crap */ + unsigned int event_done: 1; + unsigned int eof: 1; + +#if HAVE_IOCP + struct extended_overlapped *eov; +#endif +}; + +struct io_operations { + int(*iod_connect)(struct npool *nsp, int sockfd, const struct sockaddr *addr, socklen_t addrlen); + + int(*iod_read)(struct npool *nsp, int sockfd, void *buf, size_t len, int flags, + struct sockaddr *src_addr, socklen_t *addrlen); + + int(*iod_write)(struct npool *nsp, int sockfd, const void *buf, size_t len, int flags, + const struct sockaddr *dest_addr, socklen_t addrlen); +}; + +struct io_engine { + /* Human readable identifier for this engine. */ + const char *name; + + /* Engine constructor */ + int (*init)(struct npool *nsp); + + /* Engine destructor */ + void (*destroy)(struct npool *nsp); + + /* Register a new IOD to the engine */ + int(*iod_register)(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev); + + /* Remove a registered IOD */ + int(*iod_unregister)(struct npool *nsp, struct niod *iod); + + /* Modify events for a registered IOD. + * - ev_set represent the events to add + * - ev_clr represent the events to delete (if set) */ + int (*iod_modify)(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr); + + /* Main engine loop */ + int (*loop)(struct npool *nsp, int msec_timeout); + + /* I/O operations */ + struct io_operations *io_operations; +}; + +/* ----------- NSOCK I/O ENGINE CONVENIENCE WRAPPERS ------------ */ +static inline int nsock_engine_init(struct npool *nsp) { + return nsp->engine->init(nsp); +} + +static inline void nsock_engine_destroy(struct npool *nsp) { + nsp->engine->destroy(nsp); + return; +} + +static inline int nsock_engine_iod_register(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev) { + return nsp->engine->iod_register(nsp, iod, nse, ev); +} + +static inline int nsock_engine_iod_unregister(struct npool *nsp, struct niod *iod) { + return nsp->engine->iod_unregister(nsp, iod); +} + +static inline int nsock_engine_iod_modify(struct npool *nsp, struct niod *iod, struct nevent *nse, int ev_set, int ev_clr) { + return nsp->engine->iod_modify(nsp, iod, nse, ev_set, ev_clr); +} + +static inline int nsock_engine_loop(struct npool *nsp, int msec_timeout) { + return nsp->engine->loop(nsp, msec_timeout); +} + +/* ------------------- PROTOTYPES ------------------- */ + +int event_timedout(struct nevent *nse); + +/* Get a new nsock_event_id, given a type */ +nsock_event_id get_new_event_id(struct npool *nsp, enum nse_type type); + +/* Take an event ID and return the type (NSE_TYPE_CONNECT, etc */ +enum nse_type get_event_id_type(nsock_event_id event_id); + +/* Create a new event structure -- must be deleted later with event_delete, + * unless it returns NULL (failure). NULL can be passed in for the struct niod and + * the userdata if not available. */ +struct nevent *event_new(struct npool *nsp, enum nse_type type, struct niod *iod, + int timeout_msecs, nsock_ev_handler handler, void *userdata); + +/* An internal function for cancelling an event when you already have a pointer + * to the struct nevent (use nsock_event_cancel if you just have an ID). The + * event_list passed in should correspond to the type of the event. For + * example, with NSE_TYPE_READ, you would pass in &iod->read_events;. elem + * is the list element in event_list which holds the event. Pass a nonzero for + * notify if you want the program owning the event to be notified that it has + * been cancelled */ +int nevent_delete(struct npool *nsp, struct nevent *nse, gh_list_t *event_list, gh_lnode_t *elem, int notify); + +/* Adjust various statistics, dispatches the event handler (if notify is + * nonzero) and then deletes the event. This function does NOT delete the event + * from any lists it might be on (eg nsp->read_list etc.) nse->event_done + * MUST be true when you call this */ +void event_dispatch_and_delete(struct npool *nsp, struct nevent *nse, int notify); + +/* Free an struct nevent which was allocated with event_new, including all internal + * resources. Note -- we assume that nse->iod->events_pending (if it exists) + * has ALREADY been decremented (done during event_dispatch_and_delete) -- so + * remember to do this if you call event_delete() directly */ +void event_delete(struct npool *nsp, struct nevent *nse); + +/* Add an event to the appropriate nsp event list, handles housekeeping such as + * adjusting the descriptor select/poll lists, registering the timeout value, + * etc. */ +void nsock_pool_add_event(struct npool *nsp, struct nevent *nse); + +void nsock_connect_internal(struct npool *ms, struct nevent *nse, int type, int proto, struct sockaddr_storage *ss, size_t sslen, unsigned int port); + +/* Comments on using the following handle_*_result functions are available in nsock_core.c */ + +/* handle_connect_results assumes that select or poll have already shown the + * descriptor to be active */ +void handle_connect_result(struct npool *ms, struct nevent *nse, enum nse_status status); + +void handle_read_result(struct npool *ms, struct nevent *nse, enum nse_status status); + +void handle_write_result(struct npool *ms, struct nevent *nse, enum nse_status status); + +void handle_timer_result(struct npool *ms, struct nevent *nse, enum nse_status status); + +#if HAVE_PCAP +void handle_pcap_read_result(struct npool *ms, struct nevent *nse, enum nse_status status); +#endif + +/* An event has been completed and the handler is about to be called. This + * function writes out tracing data about the event if necessary */ +void nsock_trace_handler_callback(struct npool *ms, struct nevent *nse); + +#if HAVE_OPENSSL +/* Sets the ssl session of an nsock_iod, increments usage count. The session + * should not have been set yet (as no freeing is done) */ +void nsi_set_ssl_session(struct niod *iod, SSL_SESSION *sessid); +#endif + +static inline struct nevent *next_expirable_event(struct npool *nsp) { + gh_hnode_t *hnode; + + hnode = gh_heap_min(&nsp->expirables); + if (!hnode) + return NULL; + + return container_of(hnode, struct nevent, expire); +} + +static inline struct nevent *lnode_nevent(gh_lnode_t *lnode) { + return container_of(lnode, struct nevent, nodeq_io); +} + +static inline struct nevent *lnode_nevent2(gh_lnode_t *lnode) { + return container_of(lnode, struct nevent, nodeq_pcap); +} + +#endif /* NSOCK_INTERNAL_H */ + |