From 1e66fe905a948fcded4b0ba13c11e907831c835e Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 9 May 2012 15:08:36 -0500 Subject: [PATCH 01/15] Add support to Bro for connecting with peers over IPv6. - Communication::listen_ipv6 needs to be redef'd to true in order for IPv6 listening sockets to be opened. - Added Communication::listen_retry option as an interval at which to retry binding to socket addresses that were already in use. - Added some explicit baselines to check in the istate.events and istate.events-ssl tests -- the SSL test was incorrectly passing because it compared two empty files. (The files being empty because "http/base" was given as an argument to Bro which it couldn't handle because that script doesn't exist anymore). --- .../base/frameworks/communication/main.bro | 13 +- scripts/base/utils/addrs.bro | 15 + .../frameworks/communication/listen.bro | 3 +- src/IPAddr.h | 22 +- src/RemoteSerializer.cc | 362 +++++++++++------- src/RemoteSerializer.h | 27 +- src/bro.bif | 9 +- .../Baseline/istate.bro-ipv6/recv..stdout | 1 + .../Baseline/istate.bro-ipv6/send..stdout | 2 + .../Baseline/istate.events-ssl/events.rec.log | 33 ++ .../Baseline/istate.events-ssl/events.snd.log | 33 ++ .../istate.events-ssl/receiver.http.log | 2 +- .../istate.events-ssl/sender.http.log | 2 +- .../Baseline/istate.events/events.rec.log | 33 ++ .../Baseline/istate.events/events.snd.log | 33 ++ .../Baseline/istate.events/receiver.http.log | 2 +- .../Baseline/istate.events/sender.http.log | 2 +- testing/btest/istate/bro-ipv6.bro | 52 +++ testing/btest/istate/events-ssl.bro | 6 +- testing/btest/istate/events.bro | 2 + 20 files changed, 480 insertions(+), 174 deletions(-) create mode 100644 testing/btest/Baseline/istate.bro-ipv6/recv..stdout create mode 100644 testing/btest/Baseline/istate.bro-ipv6/send..stdout create mode 100644 testing/btest/Baseline/istate.events-ssl/events.rec.log create mode 100644 testing/btest/Baseline/istate.events-ssl/events.snd.log create mode 100644 testing/btest/Baseline/istate.events/events.rec.log create mode 100644 testing/btest/Baseline/istate.events/events.snd.log create mode 100644 testing/btest/istate/bro-ipv6.bro diff --git a/scripts/base/frameworks/communication/main.bro b/scripts/base/frameworks/communication/main.bro index 04772f57aa..26ec9f41b8 100644 --- a/scripts/base/frameworks/communication/main.bro +++ b/scripts/base/frameworks/communication/main.bro @@ -2,6 +2,7 @@ ##! and/or transfer events. @load base/frameworks/packet-filter +@load base/utils/addrs module Communication; @@ -10,7 +11,7 @@ export { ## The communication logging stream identifier. redef enum Log::ID += { LOG }; - ## Which interface to listen on (0.0.0.0 for any interface). + ## Which interface to listen on (``0.0.0.0`` or ``[::]`` are wildcards). const listen_interface = 0.0.0.0 &redef; ## Which port to listen on. @@ -19,6 +20,14 @@ export { ## This defines if a listening socket should use SSL. const listen_ssl = F &redef; + ## Defines if a listening socket can bind to IPv6 addresses. + const listen_ipv6 = F &redef; + + ## Defines the interval at which to retry binding to + ## :bro:id:`listen_interface` on :bro:id:`listen_port` if it's already in + ## use. + const listen_retry = 30 secs &redef; + ## Default compression level. Compression level is 0-9, with 0 = no ## compression. global compression_level = 0 &redef; @@ -160,7 +169,7 @@ event remote_log(level: count, src: count, msg: string) # This is a core generated event. event remote_log_peer(p: event_peer, level: count, src: count, msg: string) { - local rmsg = fmt("[#%d/%s:%d] %s", p$id, p$host, p$p, msg); + local rmsg = fmt("[#%d/%s:%d] %s", p$id, addr_to_uri(p$host), p$p, msg); do_script_log_common(level, src, rmsg); } diff --git a/scripts/base/utils/addrs.bro b/scripts/base/utils/addrs.bro index 415b9adfa9..08efd5281a 100644 --- a/scripts/base/utils/addrs.bro +++ b/scripts/base/utils/addrs.bro @@ -98,3 +98,18 @@ function find_ip_addresses(input: string): string_array } return output; } + +## Returns the string representation of an IP address suitable for inclusion +## in a URI. For IPv4, this does no special formatting, but for IPv6, the +## address is included in square brackets. +## +## a: the address to make suitable for URI inclusion. +## +## Returns: the string representation of *a* suitable for URI inclusion. +function addr_to_uri(a: addr): string + { + if ( is_v4_addr(a) ) + return fmt("%s", a); + else + return fmt("[%s]", a); + } diff --git a/scripts/policy/frameworks/communication/listen.bro b/scripts/policy/frameworks/communication/listen.bro index e366e5b4ff..609e8c91d6 100644 --- a/scripts/policy/frameworks/communication/listen.bro +++ b/scripts/policy/frameworks/communication/listen.bro @@ -8,5 +8,6 @@ module Communication; event bro_init() &priority=-10 { enable_communication(); - listen(listen_interface, listen_port, listen_ssl); + listen(listen_interface, listen_port, listen_ssl, listen_ipv6, + listen_retry); } diff --git a/src/IPAddr.h b/src/IPAddr.h index 8e1921e07b..447669d422 100644 --- a/src/IPAddr.h +++ b/src/IPAddr.h @@ -188,11 +188,16 @@ public: * IPv4 to IPv6 address mapping to return a full 16 bytes. * * @param bytes The pointer to a memory location in which the - * raw bytes of the address are to be copied in network byte-order. + * raw bytes of the address are to be copied. + * + * @param order The byte-order in which the returned raw bytes are copied. + * The default is network order. */ - void CopyIPv6(uint32_t* bytes) const + void CopyIPv6(uint32_t* bytes, ByteOrder order = Network) const { memcpy(bytes, in6.s6_addr, sizeof(in6.s6_addr)); + if ( order == Host ) + for ( unsigned int i = 0; i < 4; ++i ) bytes[i] = ntohl(bytes[i]); } /** @@ -280,6 +285,19 @@ public: */ string AsString() const; + /** + * Returns a string representation of the address suitable for inclusion + * in an URI. For IPv4 addresses, this is the same as AsString(), but + * IPv6 addresses are encased in square brackets. + */ + string AsURIString() const + { + if ( GetFamily() == IPv4 ) + return AsString(); + else + return string("[") + AsString() + "]"; + } + /** * Returns a host-order, plain hex string representation of the address. */ diff --git a/src/RemoteSerializer.cc b/src/RemoteSerializer.cc index 61be8a9e8f..3abec00f59 100644 --- a/src/RemoteSerializer.cc +++ b/src/RemoteSerializer.cc @@ -147,6 +147,7 @@ #include #include +#include #include #include #include @@ -195,7 +196,7 @@ extern "C" { // Gets incremented each time there's an incompatible change // to the communication internals. -static const unsigned short PROTOCOL_VERSION = 0x07; +static const unsigned short PROTOCOL_VERSION = 0x08; static const char MSG_NONE = 0x00; static const char MSG_VERSION = 0x01; @@ -458,17 +459,6 @@ static inline char* fmt_uint32s(int nargs, va_list ap) } #endif - -static inline const char* ip2a(uint32 ip) - { - static char buffer[32]; - struct in_addr addr; - - addr.s_addr = htonl(ip); - - return bro_inet_ntop(AF_INET, &addr, buffer, 32); - } - static pid_t child_pid = 0; // Return true if message type is sent by a peer (rather than the child @@ -683,24 +673,20 @@ RemoteSerializer::PeerID RemoteSerializer::Connect(const IPAddr& ip, if ( ! initialized ) reporter->InternalError("remote serializer not initialized"); - if ( ip.GetFamily() == IPv6 ) - Error("inter-Bro communication not supported over IPv6"); - - const uint32* bytes; - ip.GetBytes(&bytes); - uint32 ip4 = ntohl(*bytes); - if ( ! child_pid ) Fork(); - Peer* p = AddPeer(ip4, port); + Peer* p = AddPeer(ip, port); p->orig = true; if ( our_class ) p->our_class = our_class; - if ( ! SendToChild(MSG_CONNECT_TO, p, 5, p->id, - ip4, port, uint32(retry), use_ssl) ) + uint32 bytes[4]; + ip.CopyIPv6(bytes, IPAddr::Host); + + if ( ! SendToChild(MSG_CONNECT_TO, p, 8, p->id, bytes[0], bytes[1], + bytes[2], bytes[3], port, uint32(retry), use_ssl) ) { RemovePeer(p); return false; @@ -1232,7 +1218,8 @@ bool RemoteSerializer::SendCapabilities(Peer* peer) return caps ? SendToChild(MSG_CAPS, peer, 3, caps, 0, 0) : true; } -bool RemoteSerializer::Listen(const IPAddr& ip, uint16 port, bool expect_ssl) +bool RemoteSerializer::Listen(const IPAddr& ip, uint16 port, bool expect_ssl, + bool ipv6, double retry) { if ( ! using_communication ) return true; @@ -1240,14 +1227,15 @@ bool RemoteSerializer::Listen(const IPAddr& ip, uint16 port, bool expect_ssl) if ( ! initialized ) reporter->InternalError("remote serializer not initialized"); - if ( ip.GetFamily() == IPv6 ) - Error("inter-Bro communication not supported over IPv6"); + if ( ! ipv6 && ip.GetFamily() == IPv6 && + ip != IPAddr("0.0.0.0") && ip != IPAddr("::") ) + reporter->FatalError("Attempt to listen on address %s, but IPv6 communication disabled", ip.AsString().c_str()); - const uint32* bytes; - ip.GetBytes(&bytes); - uint32 ip4 = ntohl(*bytes); + uint32 bytes[4]; + ip.CopyIPv6(bytes, IPAddr::Host); - if ( ! SendToChild(MSG_LISTEN, 0, 3, ip4, port, expect_ssl) ) + if ( ! SendToChild(MSG_LISTEN, 0, 8, bytes[0], bytes[1], bytes[2], bytes[3], + port, expect_ssl, ipv6, (uint32) retry) ) return false; listening = true; @@ -1784,7 +1772,7 @@ RecordVal* RemoteSerializer::MakePeerVal(Peer* peer) RecordVal* v = new RecordVal(::peer); v->Assign(0, new Val(uint32(peer->id), TYPE_COUNT)); // Sic! Network order for AddrVal, host order for PortVal. - v->Assign(1, new AddrVal(htonl(peer->ip))); + v->Assign(1, new AddrVal(peer->ip)); v->Assign(2, new PortVal(peer->port, TRANSPORT_TCP)); v->Assign(3, new Val(false, TYPE_BOOL)); v->Assign(4, new StringVal("")); // set when received @@ -1793,8 +1781,8 @@ RecordVal* RemoteSerializer::MakePeerVal(Peer* peer) return v; } -RemoteSerializer::Peer* RemoteSerializer::AddPeer(uint32 ip, uint16 port, - PeerID id) +RemoteSerializer::Peer* RemoteSerializer::AddPeer(const IPAddr& ip, uint16 port, + PeerID id) { Peer* peer = new Peer; peer->id = id != PEER_NONE ? id : id_counter++; @@ -1960,8 +1948,8 @@ bool RemoteSerializer::ProcessConnected() { // IP and port follow. uint32* args = (uint32*) current_args->data; - uint32 host = ntohl(args[0]); // ### Fix: only works for IPv4 - uint16 port = (uint16) ntohl(args[1]); + IPAddr host = IPAddr(IPv6, args, IPAddr::Network); + uint16 port = (uint16) ntohl(args[4]); if ( ! current_peer ) { @@ -2980,7 +2968,8 @@ void RemoteSerializer::Log(LogLevel level, const char* msg, Peer* peer, if ( peer ) len += snprintf(buffer + len, sizeof(buffer) - len, "[#%d/%s:%d] ", - int(peer->id), ip2a(peer->ip), peer->port); + int(peer->id), peer->ip.AsURIString().c_str(), + peer->port); len += safe_snprintf(buffer + len, sizeof(buffer) - len, "%s", msg); @@ -3266,8 +3255,10 @@ SocketComm::SocketComm() terminating = false; killing = false; - listen_fd_clear = -1; - listen_fd_ssl = -1; + listen_port = 0; + listen_ssl = false; + enable_ipv6 = false; + bind_retry_interval = 0; listen_next_try = 0; // We don't want to use the signal handlers of our parent. @@ -3290,8 +3281,7 @@ SocketComm::~SocketComm() delete peers[i]->io; delete io; - close(listen_fd_clear); - close(listen_fd_ssl); + CloseListenFDs(); } static unsigned int first_rtime = 0; @@ -3340,20 +3330,13 @@ void SocketComm::Run() } if ( listen_next_try && time(0) > listen_next_try ) - Listen(listen_if, listen_port, listen_ssl); + Listen(); - if ( listen_fd_clear >= 0 ) + for ( size_t i = 0; i < listen_fds.size(); ++i ) { - FD_SET(listen_fd_clear, &fd_read); - if ( listen_fd_clear > max_fd ) - max_fd = listen_fd_clear; - } - - if ( listen_fd_ssl >= 0 ) - { - FD_SET(listen_fd_ssl, &fd_read); - if ( listen_fd_ssl > max_fd ) - max_fd = listen_fd_ssl; + FD_SET(listen_fds[i], &fd_read); + if ( listen_fds[i] > max_fd ) + max_fd = listen_fds[i]; } if ( io->IsFillingUp() && ! shutting_conns_down ) @@ -3442,12 +3425,9 @@ void SocketComm::Run() } } - if ( listen_fd_clear >= 0 && - FD_ISSET(listen_fd_clear, &fd_read) ) - AcceptConnection(listen_fd_clear); - - if ( listen_fd_ssl >= 0 && FD_ISSET(listen_fd_ssl, &fd_read) ) - AcceptConnection(listen_fd_ssl); + for ( size_t i = 0; i < listen_fds.size(); ++i ) + if ( FD_ISSET(listen_fds[i], &fd_read) ) + AcceptConnection(listen_fds[i]); // Hack to display CPU usage of the child, triggered via // SIGPROF. @@ -3571,13 +3551,8 @@ bool SocketComm::DoParentMessage() case MSG_LISTEN_STOP: { - if ( listen_fd_ssl >= 0 ) - close(listen_fd_ssl); + CloseListenFDs(); - if ( listen_fd_clear >= 0 ) - close(listen_fd_clear); - - listen_fd_clear = listen_fd_ssl = -1; Log("stopped listening"); return true; @@ -3721,10 +3696,10 @@ bool SocketComm::ProcessConnectTo() Peer* peer = new Peer; peer->id = ntohl(args[0]); - peer->ip = ntohl(args[1]); - peer->port = ntohl(args[2]); - peer->retry = ntohl(args[3]); - peer->ssl = ntohl(args[4]); + peer->ip = IPAddr(IPv6, &args[1], IPAddr::Network); + peer->port = ntohl(args[5]); + peer->retry = ntohl(args[6]); + peer->ssl = ntohl(args[7]); return Connect(peer); } @@ -3734,11 +3709,13 @@ bool SocketComm::ProcessListen() assert(parent_args); uint32* args = (uint32*) parent_args->data; - uint32 addr = ntohl(args[0]); - uint16 port = uint16(ntohl(args[1])); - uint32 ssl = ntohl(args[2]); + listen_if = IPAddr(IPv6, args, IPAddr::Network); + listen_port = uint16(ntohl(args[4])); + listen_ssl = ntohl(args[5]) != 0; + enable_ipv6 = ntohl(args[6]) != 0; + bind_retry_interval = ntohl(args[7]); - return Listen(addr, port, ssl); + return Listen(); } bool SocketComm::ProcessParentCompress() @@ -3900,29 +3877,53 @@ bool SocketComm::ProcessPeerCompress(Peer* peer) bool SocketComm::Connect(Peer* peer) { - struct sockaddr_in server; + int status; + addrinfo hints, *res, *res0; + bzero(&hints, sizeof(hints)); - int sockfd = socket(PF_INET, SOCK_STREAM, 0); - if ( sockfd < 0 ) + hints.ai_family = PF_UNSPEC; + hints.ai_protocol = IPPROTO_TCP; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_NUMERICHOST; + + char port_str[16]; + modp_uitoa10(peer->port, port_str); + + // TODO: better to accept string arguments from the user to pass into + // getaddrinfo? This might make it easier to explicitly connect to + // non-global IPv6 addresses with a scope zone identifier (RFC 4007). + status = getaddrinfo(peer->ip.AsString().c_str(), port_str, &hints, &res0); + if ( status != 0 ) { - Error(fmt("can't create socket, %s", strerror(errno))); + Error(fmt("getaddrinfo error: %s", gai_strerror(status))); return false; } - bzero(&server, sizeof(server)); - server.sin_family = AF_INET; - server.sin_port = htons(peer->port); - server.sin_addr.s_addr = htonl(peer->ip); - - bool connected = true; - - if ( connect(sockfd, (sockaddr*) &server, sizeof(server)) < 0 ) + int sockfd = -1; + for ( res = res0; res; res = res->ai_next ) { - Error(fmt("connect failed: %s", strerror(errno)), peer); - close(sockfd); - connected = false; + sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if ( sockfd < 0 ) + { + Error(fmt("can't create connect socket, %s", strerror(errno))); + continue; + } + + if ( connect(sockfd, res->ai_addr, res->ai_addrlen) < 0 ) + { + Error(fmt("connect failed: %s", strerror(errno)), peer); + close(sockfd); + sockfd = -1; + continue; + } + + break; } + freeaddrinfo(res0); + + bool connected = sockfd != -1; + if ( ! (connected || peer->retry) ) { CloseConnection(peer, false); @@ -3947,9 +3948,7 @@ bool SocketComm::Connect(Peer* peer) if ( connected ) { if ( peer->ssl ) - { peer->io = new ChunkedIOSSL(sockfd, false); - } else peer->io = new ChunkedIOFd(sockfd, "child->peer"); @@ -3964,7 +3963,12 @@ bool SocketComm::Connect(Peer* peer) if ( connected ) { Log("connected", peer); - if ( ! SendToParent(MSG_CONNECTED, peer, 2, peer->ip, peer->port) ) + + uint32 bytes[4]; + peer->ip.CopyIPv6(bytes, IPAddr::Host); + + if ( ! SendToParent(MSG_CONNECTED, peer, 5, bytes[0], bytes[1], + bytes[2], bytes[3], peer->port) ) return false; } @@ -4001,86 +4005,139 @@ bool SocketComm::CloseConnection(Peer* peer, bool reconnect) return true; } -bool SocketComm::Listen(uint32 ip, uint16 port, bool expect_ssl) +bool SocketComm::Listen() { - int* listen_fd = expect_ssl ? &listen_fd_ssl : &listen_fd_clear; + int status, on = 1; + addrinfo hints, *res, *res0; + bzero(&hints, sizeof(hints)); - if ( *listen_fd >= 0 ) - close(*listen_fd); - - struct sockaddr_in server; - - *listen_fd = socket(PF_INET, SOCK_STREAM, 0); - if ( *listen_fd < 0 ) + if ( enable_ipv6 ) { - Error(fmt("can't create listen socket, %s", - strerror(errno))); + if ( listen_if == IPAddr("0.0.0.0") || listen_if == IPAddr("::") ) + hints.ai_family = PF_UNSPEC; + else + hints.ai_family = listen_if.GetFamily() == IPv4 ? PF_INET : PF_INET6; + } + else + hints.ai_family = PF_INET; + + hints.ai_protocol = IPPROTO_TCP; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICHOST; + + char port_str[16]; + modp_uitoa10(listen_port, port_str); + + const char* addr_str = 0; + if ( listen_if != IPAddr("0.0.0.0") && listen_if != IPAddr("::") ) + addr_str = listen_if.AsString().c_str(); + + CloseListenFDs(); + + // TODO: better to accept string arguments from the user to pass into + // getaddrinfo? This might make it easier to explicitly bind to a + // non-global IPv6 address with a scope zone identifier (RFC 4007). + if ( (status = getaddrinfo(addr_str, port_str, &hints, &res0)) != 0 ) + { + Error(fmt("getaddrinfo error: %s", gai_strerror(status))); return false; } - // Set SO_REUSEADDR. - int turn_on = 1; - if ( setsockopt(*listen_fd, SOL_SOCKET, SO_REUSEADDR, - &turn_on, sizeof(turn_on)) < 0 ) + for ( res = res0; res; res = res->ai_next ) { - Error(fmt("can't set SO_REUSEADDR, %s", - strerror(errno))); - return false; - } - - bzero(&server, sizeof(server)); - server.sin_family = AF_INET; - server.sin_port = htons(port); - server.sin_addr.s_addr = htonl(ip); - - if ( bind(*listen_fd, (sockaddr*) &server, sizeof(server)) < 0 ) - { - Error(fmt("can't bind to port %d, %s", port, strerror(errno))); - close(*listen_fd); - *listen_fd = -1; - - if ( errno == EADDRINUSE ) + if ( res->ai_family != AF_INET && res->ai_family != AF_INET6 ) { - listen_if = ip; - listen_port = port; - listen_ssl = expect_ssl; - // FIXME: Make this timeout configurable. - listen_next_try = time(0) + 30; + Error(fmt("can't create listen socket: unknown address family, %d", + res->ai_family)); + continue; } - return false; + + IPAddr a = res->ai_family == AF_INET ? + IPAddr(((sockaddr_in*)res->ai_addr)->sin_addr) : + IPAddr(((sockaddr_in6*)res->ai_addr)->sin6_addr); + + int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if ( fd < 0 ) + { + Error(fmt("can't create listen socket, %s", strerror(errno))); + continue; + } + + if ( setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0 ) + Error(fmt("can't set SO_REUSEADDR, %s", strerror(errno))); + + // For IPv6 listening sockets, we don't want do dual binding to also + // get IPv4-mapped addresses because that's not as portable. e.g. + // many BSDs don't allow that. + if ( res->ai_family == AF_INET6 && + setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &on, sizeof(on)) < 0 ) + Error(fmt("can't set IPV6_V6ONLY, %s", strerror(errno))); + + if ( bind(fd, res->ai_addr, res->ai_addrlen) < 0 ) + { + Error(fmt("can't bind to %s:%s, %s", a.AsURIString().c_str(), + port_str, strerror(errno))); + close(fd); + + if ( errno == EADDRINUSE ) + { + // Abandon completely this attempt to set up listening sockets, + // try again later. + CloseListenFDs(); + listen_next_try = time(0) + bind_retry_interval; + return false; + } + continue; + } + + if ( listen(fd, 50) < 0 ) + { + Error(fmt("can't listen on %s:%s, %s", a.AsURIString().c_str(), + port_str, strerror(errno))); + close(fd); + continue; + } + + listen_fds.push_back(fd); + Log(fmt("listening on %s:%s (%s)", a.AsURIString().c_str(), port_str, + listen_ssl ? "ssl" : "clear")); } - if ( listen(*listen_fd, 50) < 0 ) - { - Error(fmt("can't listen, %s", strerror(errno))); - return false; - } + freeaddrinfo(res0); listen_next_try = 0; - Log(fmt("listening on %s:%d (%s)", - ip2a(ip), port, expect_ssl ? "ssl" : "clear")); - return true; + return listen_fds.size() > 0; } bool SocketComm::AcceptConnection(int fd) { - sockaddr_in client; + sockaddr_storage client; socklen_t len = sizeof(client); int clientfd = accept(fd, (sockaddr*) &client, &len); if ( clientfd < 0 ) { - Error(fmt("accept failed, %s %d", - strerror(errno), errno)); + Error(fmt("accept failed, %s %d", strerror(errno), errno)); + return false; + } + + if ( client.ss_family != AF_INET && client.ss_family != AF_INET6 ) + { + Error(fmt("accept fail, unknown address family %d", client.ss_family)); + close(clientfd); return false; } Peer* peer = new Peer; peer->id = id_counter++; - peer->ip = ntohl(client.sin_addr.s_addr); - peer->port = ntohs(client.sin_port); + peer->ip = client.ss_family == AF_INET ? + IPAddr(((sockaddr_in*)&client)->sin_addr) : + IPAddr(((sockaddr_in6*)&client)->sin6_addr); + peer->port = client.ss_family == AF_INET ? + ntohs(((sockaddr_in*)&client)->sin_port) : + ntohs(((sockaddr_in6*)&client)->sin6_port); peer->connected = true; - peer->ssl = (fd == listen_fd_ssl); + peer->ssl = listen_ssl; peer->compressor = false; if ( peer->ssl ) @@ -4090,8 +4147,7 @@ bool SocketComm::AcceptConnection(int fd) if ( ! peer->io->Init() ) { - Error(fmt("can't init peer io: %s", - peer->io->Error()), false); + Error(fmt("can't init peer io: %s", peer->io->Error()), false); return false; } @@ -4099,7 +4155,11 @@ bool SocketComm::AcceptConnection(int fd) Log(fmt("accepted %s connection", peer->ssl ? "SSL" : "clear"), peer); - if ( ! SendToParent(MSG_CONNECTED, peer, 2, peer->ip, peer->port) ) + uint32 bytes[4]; + peer->ip.CopyIPv6(bytes, IPAddr::Host); + + if ( ! SendToParent(MSG_CONNECTED, peer, 5, bytes[0], bytes[1], bytes[2], + bytes[3], peer->port) ) return false; return true; @@ -4117,12 +4177,19 @@ const char* SocketComm::MakeLogString(const char* msg, Peer* peer) if ( peer ) len = snprintf(buffer, BUFSIZE, "[#%d/%s:%d] ", int(peer->id), - ip2a(peer->ip), peer->port); + peer->ip.AsURIString().c_str(), peer->port); len += safe_snprintf(buffer + len, BUFSIZE - len, "%s", msg); return buffer; } +void SocketComm::CloseListenFDs() + { + for ( size_t i = 0; i < listen_fds.size(); ++i ) + close(listen_fds[i]); + listen_fds.clear(); + } + void SocketComm::Error(const char* msg, bool kill_me) { if ( kill_me ) @@ -4165,7 +4232,7 @@ void SocketComm::Log(const char* msg, Peer* peer) void SocketComm::InternalError(const char* msg) { - fprintf(stderr, "interal error in child: %s\n", msg); + fprintf(stderr, "internal error in child: %s\n", msg); Kill(); } @@ -4180,8 +4247,7 @@ void SocketComm::Kill() LogProf(); Log("terminating"); - close(listen_fd_clear); - close(listen_fd_ssl); + CloseListenFDs(); kill(getpid(), SIGTERM); diff --git a/src/RemoteSerializer.h b/src/RemoteSerializer.h index 05d25ca525..f6f94f53d3 100644 --- a/src/RemoteSerializer.h +++ b/src/RemoteSerializer.h @@ -10,8 +10,7 @@ #include "Stats.h" #include "File.h" -// All IP arguments are in host byte-order. -// FIXME: Change this to network byte order +#include class IncrementalSendTimer; @@ -63,7 +62,8 @@ public: bool CompleteHandshake(PeerID peer); // Start to listen. - bool Listen(const IPAddr& ip, uint16 port, bool expect_ssl); + bool Listen(const IPAddr& ip, uint16 port, bool expect_ssl, bool ipv6, + double retry); // Stop it. bool StopListening(); @@ -179,9 +179,7 @@ protected: struct Peer { PeerID id; // Unique ID (non-zero) per peer. - // ### Fix: currently, we only work for IPv4. - // addr_type ip; - uint32 ip; + IPAddr ip; uint16 port; handler_list handlers; @@ -277,7 +275,7 @@ protected: bool ProcessLogWrite(); bool ProcessRequestLogs(); - Peer* AddPeer(uint32 ip, uint16 port, PeerID id = PEER_NONE); + Peer* AddPeer(const IPAddr& ip, uint16 port, PeerID id = PEER_NONE); Peer* LookupPeer(PeerID id, bool only_if_connected); void RemovePeer(Peer* peer); bool IsConnectedPeer(PeerID id); @@ -412,7 +410,6 @@ protected: { id = 0; io = 0; - ip = 0; port = 0; state = 0; connected = false; @@ -424,7 +421,7 @@ protected: RemoteSerializer::PeerID id; ChunkedIO* io; - uint32 ip; + IPAddr ip; uint16 port; char state; bool connected; @@ -437,7 +434,7 @@ protected: bool compressor; }; - bool Listen(uint32 ip, uint16 port, bool expect_ssl); + bool Listen(); bool AcceptConnection(int listen_fd); bool Connect(Peer* peer); bool CloseConnection(Peer* peer, bool reconnect); @@ -482,6 +479,9 @@ protected: bool ForwardChunkToPeer(); const char* MakeLogString(const char* msg, Peer *peer); + // Closes all file descriptors associated with listening sockets. + void CloseListenFDs(); + // Peers we are communicating with: declare(PList, Peer); typedef PList(Peer) peer_list; @@ -498,14 +498,15 @@ protected: char parent_msgtype; ChunkedIO::Chunk* parent_args; - int listen_fd_clear; - int listen_fd_ssl; + vector listen_fds; // If the port we're trying to bind to is already in use, we will retry // it regularly. - uint32 listen_if; // Fix: only supports IPv4 + IPAddr listen_if; uint16 listen_port; bool listen_ssl; + bool enable_ipv6; // allow IPv6 listen sockets + uint32 bind_retry_interval; time_t listen_next_try; bool shutting_conns_down; bool terminating; diff --git a/src/bro.bif b/src/bro.bif index 15740a83c7..3f4215dc13 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -5402,12 +5402,17 @@ function set_compression_level%(p: event_peer, level: count%) : bool ## ## ssl: If true, Bro uses SSL to encrypt the session. ## +## ipv6: If true, enable listening on IPv6 addresses. +## +## retry_interval: If address *ip* is found to be already in use, this is +## the interval at which to automatically retry binding. +## ## Returns: True on success. ## ## .. bro:see:: connect disconnect -function listen%(ip: addr, p: port, ssl: bool %) : bool +function listen%(ip: addr, p: port, ssl: bool, ipv6: bool, retry_interval: interval%) : bool %{ - return new Val(remote_serializer->Listen(ip->AsAddr(), p->Port(), ssl), TYPE_BOOL); + return new Val(remote_serializer->Listen(ip->AsAddr(), p->Port(), ssl, ipv6, retry_interval), TYPE_BOOL); %} ## Checks whether the last raised event came from a remote peer. diff --git a/testing/btest/Baseline/istate.bro-ipv6/recv..stdout b/testing/btest/Baseline/istate.bro-ipv6/recv..stdout new file mode 100644 index 0000000000..673af68234 --- /dev/null +++ b/testing/btest/Baseline/istate.bro-ipv6/recv..stdout @@ -0,0 +1 @@ +handshake done with peer: ::1 diff --git a/testing/btest/Baseline/istate.bro-ipv6/send..stdout b/testing/btest/Baseline/istate.bro-ipv6/send..stdout new file mode 100644 index 0000000000..fbc855464d --- /dev/null +++ b/testing/btest/Baseline/istate.bro-ipv6/send..stdout @@ -0,0 +1,2 @@ +handshake done with peer: ::1 +my_event: hello world diff --git a/testing/btest/Baseline/istate.events-ssl/events.rec.log b/testing/btest/Baseline/istate.events-ssl/events.rec.log new file mode 100644 index 0000000000..04993fb84a --- /dev/null +++ b/testing/btest/Baseline/istate.events-ssl/events.rec.log @@ -0,0 +1,33 @@ +http_request +http_begin_entity +http_header +http_header +http_header +http_header +http_all_headers +http_content_type +http_end_entity +http_message_done +http_signature_found +http_reply +http_begin_entity +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_all_headers +http_content_type +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_end_entity +http_message_done diff --git a/testing/btest/Baseline/istate.events-ssl/events.snd.log b/testing/btest/Baseline/istate.events-ssl/events.snd.log new file mode 100644 index 0000000000..04993fb84a --- /dev/null +++ b/testing/btest/Baseline/istate.events-ssl/events.snd.log @@ -0,0 +1,33 @@ +http_request +http_begin_entity +http_header +http_header +http_header +http_header +http_all_headers +http_content_type +http_end_entity +http_message_done +http_signature_found +http_reply +http_begin_entity +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_all_headers +http_content_type +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_end_entity +http_message_done diff --git a/testing/btest/Baseline/istate.events-ssl/receiver.http.log b/testing/btest/Baseline/istate.events-ssl/receiver.http.log index 1601f8ad3c..5a7912d23d 100644 --- a/testing/btest/Baseline/istate.events-ssl/receiver.http.log +++ b/testing/btest/Baseline/istate.events-ssl/receiver.http.log @@ -5,4 +5,4 @@ #path http #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer user_agent request_body_len response_body_len status_code status_msg info_code info_msg filename tags username password proxied mime_type md5 extraction_file #types time string addr port addr port count string string string string string count count count string count string string table[enum] string string table[string] string string file -1324314406.995958 arKYeMETxOg 141.42.64.125 56730 125.190.109.199 80 1 GET www.icir.org / - Wget/1.10 0 9130 200 OK - - - (empty) - - - text/html - - +1336588614.060989 arKYeMETxOg 141.42.64.125 56730 125.190.109.199 80 1 GET www.icir.org / - Wget/1.10 0 9130 200 OK - - - (empty) - - - text/html - - diff --git a/testing/btest/Baseline/istate.events-ssl/sender.http.log b/testing/btest/Baseline/istate.events-ssl/sender.http.log index 1601f8ad3c..5a7912d23d 100644 --- a/testing/btest/Baseline/istate.events-ssl/sender.http.log +++ b/testing/btest/Baseline/istate.events-ssl/sender.http.log @@ -5,4 +5,4 @@ #path http #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer user_agent request_body_len response_body_len status_code status_msg info_code info_msg filename tags username password proxied mime_type md5 extraction_file #types time string addr port addr port count string string string string string count count count string count string string table[enum] string string table[string] string string file -1324314406.995958 arKYeMETxOg 141.42.64.125 56730 125.190.109.199 80 1 GET www.icir.org / - Wget/1.10 0 9130 200 OK - - - (empty) - - - text/html - - +1336588614.060989 arKYeMETxOg 141.42.64.125 56730 125.190.109.199 80 1 GET www.icir.org / - Wget/1.10 0 9130 200 OK - - - (empty) - - - text/html - - diff --git a/testing/btest/Baseline/istate.events/events.rec.log b/testing/btest/Baseline/istate.events/events.rec.log new file mode 100644 index 0000000000..04993fb84a --- /dev/null +++ b/testing/btest/Baseline/istate.events/events.rec.log @@ -0,0 +1,33 @@ +http_request +http_begin_entity +http_header +http_header +http_header +http_header +http_all_headers +http_content_type +http_end_entity +http_message_done +http_signature_found +http_reply +http_begin_entity +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_all_headers +http_content_type +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_end_entity +http_message_done diff --git a/testing/btest/Baseline/istate.events/events.snd.log b/testing/btest/Baseline/istate.events/events.snd.log new file mode 100644 index 0000000000..04993fb84a --- /dev/null +++ b/testing/btest/Baseline/istate.events/events.snd.log @@ -0,0 +1,33 @@ +http_request +http_begin_entity +http_header +http_header +http_header +http_header +http_all_headers +http_content_type +http_end_entity +http_message_done +http_signature_found +http_reply +http_begin_entity +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_header +http_all_headers +http_content_type +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_entity_data +http_end_entity +http_message_done diff --git a/testing/btest/Baseline/istate.events/receiver.http.log b/testing/btest/Baseline/istate.events/receiver.http.log index 25a7f289c0..55a0189cec 100644 --- a/testing/btest/Baseline/istate.events/receiver.http.log +++ b/testing/btest/Baseline/istate.events/receiver.http.log @@ -5,4 +5,4 @@ #path http #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer user_agent request_body_len response_body_len status_code status_msg info_code info_msg filename tags username password proxied mime_type md5 extraction_file #types time string addr port addr port count string string string string string count count count string count string string table[enum] string string table[string] string string file -1324314415.616486 arKYeMETxOg 141.42.64.125 56730 125.190.109.199 80 1 GET www.icir.org / - Wget/1.10 0 9130 200 OK - - - (empty) - - - text/html - - +1336587178.164598 arKYeMETxOg 141.42.64.125 56730 125.190.109.199 80 1 GET www.icir.org / - Wget/1.10 0 9130 200 OK - - - (empty) - - - text/html - - diff --git a/testing/btest/Baseline/istate.events/sender.http.log b/testing/btest/Baseline/istate.events/sender.http.log index 25a7f289c0..55a0189cec 100644 --- a/testing/btest/Baseline/istate.events/sender.http.log +++ b/testing/btest/Baseline/istate.events/sender.http.log @@ -5,4 +5,4 @@ #path http #fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p trans_depth method host uri referrer user_agent request_body_len response_body_len status_code status_msg info_code info_msg filename tags username password proxied mime_type md5 extraction_file #types time string addr port addr port count string string string string string count count count string count string string table[enum] string string table[string] string string file -1324314415.616486 arKYeMETxOg 141.42.64.125 56730 125.190.109.199 80 1 GET www.icir.org / - Wget/1.10 0 9130 200 OK - - - (empty) - - - text/html - - +1336587178.164598 arKYeMETxOg 141.42.64.125 56730 125.190.109.199 80 1 GET www.icir.org / - Wget/1.10 0 9130 200 OK - - - (empty) - - - text/html - - diff --git a/testing/btest/istate/bro-ipv6.bro b/testing/btest/istate/bro-ipv6.bro new file mode 100644 index 0000000000..6230018636 --- /dev/null +++ b/testing/btest/istate/bro-ipv6.bro @@ -0,0 +1,52 @@ +# @TEST-GROUP: comm +# +# @TEST-REQUIRES: ifconfig | grep -q "inet6 ::1" +# +# @TEST-EXEC: btest-bg-run recv bro -b ../recv.bro +# @TEST-EXEC: btest-bg-run send bro -b ../send.bro +# @TEST-EXEC: btest-bg-wait -k 20 +# +# @TEST-EXEC: btest-diff recv/.stdout +# @TEST-EXEC: btest-diff send/.stdout + +@TEST-START-FILE send.bro + +@load base/frameworks/communication + +redef Communication::nodes += { + ["foo"] = [$host=[::1], $connect=T, $events=/my_event/] +}; + +global my_event: event(s: string); + +event remote_connection_handshake_done(p: event_peer) + { + print fmt("handshake done with peer: %s", p$host); + } + +event my_event(s: string) + { + print fmt("my_event: %s", s); + terminate(); + } + +@TEST-END-FILE + +############# + +@TEST-START-FILE recv.bro + +@load frameworks/communication/listen + +redef Communication::listen_ipv6=T; + +global my_event: event(s: string); + +event remote_connection_handshake_done(p: event_peer) + { + print fmt("handshake done with peer: %s", p$host); + event my_event("hello world"); + terminate(); + } + +@TEST-END-FILE diff --git a/testing/btest/istate/events-ssl.bro b/testing/btest/istate/events-ssl.bro index 25aa2dc8fb..c86087df81 100644 --- a/testing/btest/istate/events-ssl.bro +++ b/testing/btest/istate/events-ssl.bro @@ -8,8 +8,10 @@ # @TEST-EXEC: btest-diff receiver/http.log # @TEST-EXEC: cmp sender/http.log receiver/http.log # -# @TEST-EXEC: bro -x sender/events.bst http/base | sed 's/^Event \[[-0-9.]*\] //g' | grep '^http_' | grep -v http_stats | sed 's/(.*$//g' >events.snd.log -# @TEST-EXEC: bro -x receiver/events.bst http/base | sed 's/^Event \[[-0-9.]*\] //g' | grep '^http_' | grep -v http_stats | sed 's/(.*$//g' >events.rec.log +# @TEST-EXEC: bro -x sender/events.bst | sed 's/^Event \[[-0-9.]*\] //g' | grep '^http_' | grep -v http_stats | sed 's/(.*$//g' >events.snd.log +# @TEST-EXEC: bro -x receiver/events.bst | sed 's/^Event \[[-0-9.]*\] //g' | grep '^http_' | grep -v http_stats | sed 's/(.*$//g' >events.rec.log +# @TEST-EXEC: btest-diff events.rec.log +# @TEST-EXEC: btest-diff events.snd.log # @TEST-EXEC: cmp events.rec.log events.snd.log # # We don't compare the transmitted event paramerters anymore. With the dynamic diff --git a/testing/btest/istate/events.bro b/testing/btest/istate/events.bro index 81a1d765db..6d8227c810 100644 --- a/testing/btest/istate/events.bro +++ b/testing/btest/istate/events.bro @@ -10,6 +10,8 @@ # # @TEST-EXEC: bro -x sender/events.bst | sed 's/^Event \[[-0-9.]*\] //g' | grep '^http_' | grep -v http_stats | sed 's/(.*$//g' >events.snd.log # @TEST-EXEC: bro -x receiver/events.bst | sed 's/^Event \[[-0-9.]*\] //g' | grep '^http_' | grep -v http_stats | sed 's/(.*$//g' >events.rec.log +# @TEST-EXEC: btest-diff events.rec.log +# @TEST-EXEC: btest-diff events.snd.log # @TEST-EXEC: cmp events.rec.log events.snd.log # # We don't compare the transmitted event paramerters anymore. With the dynamic From 8bb62eaaa2df13adf1de74081ca4f8b1dfc66423 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 9 May 2012 16:09:16 -0500 Subject: [PATCH 02/15] Undo communication protocol version bump. Looks like it wasn't necessary because no message between remote peers needed to be changed to support IPv6, just messages between Bro parent and child processes were changed. --- src/RemoteSerializer.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/RemoteSerializer.cc b/src/RemoteSerializer.cc index 3abec00f59..0383977de1 100644 --- a/src/RemoteSerializer.cc +++ b/src/RemoteSerializer.cc @@ -196,7 +196,7 @@ extern "C" { // Gets incremented each time there's an incompatible change // to the communication internals. -static const unsigned short PROTOCOL_VERSION = 0x08; +static const unsigned short PROTOCOL_VERSION = 0x07; static const char MSG_NONE = 0x00; static const char MSG_VERSION = 0x01; From 2338a322882e966c9f1ce673ae3f180b153f73bd Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 10 May 2012 10:47:39 -0500 Subject: [PATCH 03/15] Remove AI_ADDRCONFIG getaddrinfo hints flag for listening sockets. Because, according to RFC 3493, that will cause getaddrinfo to overlook the ::1 loopback if there's not some other interface with a global IPv6 address. The rationale being that the flag helps prevent unnecessary AAAA lookups, but since I set AI_NUMERICHOST, lookups aren't going to happen anyway. Also update the IPv6 Bro communication test to get it to work more reliably. --- src/RemoteSerializer.cc | 2 +- .../recv..stdout | 0 .../send..stdout | 0 .../btest/istate/{bro-ipv6.bro => bro-ipv6-socket.bro} | 8 ++++++-- 4 files changed, 7 insertions(+), 3 deletions(-) rename testing/btest/Baseline/{istate.bro-ipv6 => istate.bro-ipv6-socket}/recv..stdout (100%) rename testing/btest/Baseline/{istate.bro-ipv6 => istate.bro-ipv6-socket}/send..stdout (100%) rename testing/btest/istate/{bro-ipv6.bro => bro-ipv6-socket.bro} (88%) diff --git a/src/RemoteSerializer.cc b/src/RemoteSerializer.cc index 0383977de1..9123e99ef4 100644 --- a/src/RemoteSerializer.cc +++ b/src/RemoteSerializer.cc @@ -4023,7 +4023,7 @@ bool SocketComm::Listen() hints.ai_protocol = IPPROTO_TCP; hints.ai_socktype = SOCK_STREAM; - hints.ai_flags = AI_PASSIVE | AI_ADDRCONFIG | AI_NUMERICHOST; + hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST; char port_str[16]; modp_uitoa10(listen_port, port_str); diff --git a/testing/btest/Baseline/istate.bro-ipv6/recv..stdout b/testing/btest/Baseline/istate.bro-ipv6-socket/recv..stdout similarity index 100% rename from testing/btest/Baseline/istate.bro-ipv6/recv..stdout rename to testing/btest/Baseline/istate.bro-ipv6-socket/recv..stdout diff --git a/testing/btest/Baseline/istate.bro-ipv6/send..stdout b/testing/btest/Baseline/istate.bro-ipv6-socket/send..stdout similarity index 100% rename from testing/btest/Baseline/istate.bro-ipv6/send..stdout rename to testing/btest/Baseline/istate.bro-ipv6-socket/send..stdout diff --git a/testing/btest/istate/bro-ipv6.bro b/testing/btest/istate/bro-ipv6-socket.bro similarity index 88% rename from testing/btest/istate/bro-ipv6.bro rename to testing/btest/istate/bro-ipv6-socket.bro index 6230018636..ae77a42c54 100644 --- a/testing/btest/istate/bro-ipv6.bro +++ b/testing/btest/istate/bro-ipv6-socket.bro @@ -1,11 +1,11 @@ # @TEST-GROUP: comm # -# @TEST-REQUIRES: ifconfig | grep -q "inet6 ::1" +# @TEST-REQUIRES: ifconfig | grep -q -E "inet6 ::1|inet6 addr: ::1" # # @TEST-EXEC: btest-bg-run recv bro -b ../recv.bro # @TEST-EXEC: btest-bg-run send bro -b ../send.bro # @TEST-EXEC: btest-bg-wait -k 20 -# +# # @TEST-EXEC: btest-diff recv/.stdout # @TEST-EXEC: btest-diff send/.stdout @@ -46,6 +46,10 @@ event remote_connection_handshake_done(p: event_peer) { print fmt("handshake done with peer: %s", p$host); event my_event("hello world"); + } + +event remote_connection_closed(p: event_peer) + { terminate(); } From d3ea3127822e2c51edbba02a88dc49a591ef9d11 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 11 May 2012 17:16:57 -0500 Subject: [PATCH 04/15] Add unit tests for Broccoli SSL and Broccoli IPv6 connectivity. --- .../istate.broccoli-ipv6-socket/bro..stdout | 9 +++ .../broccoli..stdout | 6 ++ .../Baseline/istate.broccoli-ssl/bro..stdout | 9 +++ .../istate.broccoli-ssl/broccoli..stdout | 6 ++ testing/btest/istate/broccoli-ipv6-socket.bro | 10 +++ testing/btest/istate/broccoli-ipv6.bro | 8 +-- testing/btest/istate/broccoli-ssl.bro | 68 +++++++++++++++++++ 7 files changed, 109 insertions(+), 7 deletions(-) create mode 100644 testing/btest/Baseline/istate.broccoli-ipv6-socket/bro..stdout create mode 100644 testing/btest/Baseline/istate.broccoli-ipv6-socket/broccoli..stdout create mode 100644 testing/btest/Baseline/istate.broccoli-ssl/bro..stdout create mode 100644 testing/btest/Baseline/istate.broccoli-ssl/broccoli..stdout create mode 100644 testing/btest/istate/broccoli-ipv6-socket.bro create mode 100644 testing/btest/istate/broccoli-ssl.bro diff --git a/testing/btest/Baseline/istate.broccoli-ipv6-socket/bro..stdout b/testing/btest/Baseline/istate.broccoli-ipv6-socket/bro..stdout new file mode 100644 index 0000000000..0a7bac52c5 --- /dev/null +++ b/testing/btest/Baseline/istate.broccoli-ipv6-socket/bro..stdout @@ -0,0 +1,9 @@ +handshake done with peer +bro_addr(1.2.3.4) +bro_subnet(10.0.0.0/16) +bro_addr(2607:f8b0:4009:802::1014) +bro_subnet(2607:f8b0::/32) +broccoli_addr(1.2.3.4) +broccoli_subnet(10.0.0.0/16) +broccoli_addr(2607:f8b0:4009:802::1014) +broccoli_subnet(2607:f8b0::/32) diff --git a/testing/btest/Baseline/istate.broccoli-ipv6-socket/broccoli..stdout b/testing/btest/Baseline/istate.broccoli-ipv6-socket/broccoli..stdout new file mode 100644 index 0000000000..dba9318891 --- /dev/null +++ b/testing/btest/Baseline/istate.broccoli-ipv6-socket/broccoli..stdout @@ -0,0 +1,6 @@ +Connected to Bro instance at: ::1:47757 +Received bro_addr(1.2.3.4) +Received bro_subnet(10.0.0.0/16) +Received bro_addr(2607:f8b0:4009:802::1014) +Received bro_subnet(2607:f8b0::/32) +Terminating diff --git a/testing/btest/Baseline/istate.broccoli-ssl/bro..stdout b/testing/btest/Baseline/istate.broccoli-ssl/bro..stdout new file mode 100644 index 0000000000..0a7bac52c5 --- /dev/null +++ b/testing/btest/Baseline/istate.broccoli-ssl/bro..stdout @@ -0,0 +1,9 @@ +handshake done with peer +bro_addr(1.2.3.4) +bro_subnet(10.0.0.0/16) +bro_addr(2607:f8b0:4009:802::1014) +bro_subnet(2607:f8b0::/32) +broccoli_addr(1.2.3.4) +broccoli_subnet(10.0.0.0/16) +broccoli_addr(2607:f8b0:4009:802::1014) +broccoli_subnet(2607:f8b0::/32) diff --git a/testing/btest/Baseline/istate.broccoli-ssl/broccoli..stdout b/testing/btest/Baseline/istate.broccoli-ssl/broccoli..stdout new file mode 100644 index 0000000000..481778c98a --- /dev/null +++ b/testing/btest/Baseline/istate.broccoli-ssl/broccoli..stdout @@ -0,0 +1,6 @@ +Connected to Bro instance at: localhost:47757 +Received bro_addr(1.2.3.4) +Received bro_subnet(10.0.0.0/16) +Received bro_addr(2607:f8b0:4009:802::1014) +Received bro_subnet(2607:f8b0::/32) +Terminating diff --git a/testing/btest/istate/broccoli-ipv6-socket.bro b/testing/btest/istate/broccoli-ipv6-socket.bro new file mode 100644 index 0000000000..e36ac9e9f7 --- /dev/null +++ b/testing/btest/istate/broccoli-ipv6-socket.bro @@ -0,0 +1,10 @@ +# @TEST-GROUP: comm +# +# @TEST-REQUIRES: test -e $BUILD/aux/broccoli/src/libbroccoli.so || test -e $BUILD/aux/broccoli/src/libbroccoli.dylib +# @TEST-REQUIRES: ifconfig | grep -q -E "inet6 ::1|inet6 addr: ::1" +# +# @TEST-EXEC: btest-bg-run bro bro $DIST/aux/broccoli/test/broccoli-v6addrs.bro "Communication::listen_ipv6=T" +# @TEST-EXEC: btest-bg-run broccoli $BUILD/aux/broccoli/test/broccoli-v6addrs -6 ::1 +# @TEST-EXEC: btest-bg-wait -k 20 +# @TEST-EXEC: btest-diff bro/.stdout +# @TEST-EXEC: btest-diff broccoli/.stdout diff --git a/testing/btest/istate/broccoli-ipv6.bro b/testing/btest/istate/broccoli-ipv6.bro index b7ab5bdb05..415c8bb2d2 100644 --- a/testing/btest/istate/broccoli-ipv6.bro +++ b/testing/btest/istate/broccoli-ipv6.bro @@ -2,14 +2,8 @@ # # @TEST-REQUIRES: test -e $BUILD/aux/broccoli/src/libbroccoli.so || test -e $BUILD/aux/broccoli/src/libbroccoli.dylib # -# @TEST-EXEC: btest-bg-run bro bro %INPUT $DIST/aux/broccoli/test/broccoli-v6addrs.bro +# @TEST-EXEC: btest-bg-run bro bro $DIST/aux/broccoli/test/broccoli-v6addrs.bro # @TEST-EXEC: btest-bg-run broccoli $BUILD/aux/broccoli/test/broccoli-v6addrs # @TEST-EXEC: btest-bg-wait -k 20 # @TEST-EXEC: btest-diff bro/.stdout # @TEST-EXEC: btest-diff broccoli/.stdout - -event remote_connection_closed(p: event_peer) - { - terminate(); - } - diff --git a/testing/btest/istate/broccoli-ssl.bro b/testing/btest/istate/broccoli-ssl.bro new file mode 100644 index 0000000000..61401c483a --- /dev/null +++ b/testing/btest/istate/broccoli-ssl.bro @@ -0,0 +1,68 @@ +# @TEST-GROUP: comm +# +# @TEST-REQUIRES: test -e $BUILD/aux/broccoli/src/libbroccoli.so || test -e $BUILD/aux/broccoli/src/libbroccoli.dylib +# +# @TEST-EXEC: chmod 600 broccoli.conf +# @TEST-EXEC: btest-bg-run bro bro $DIST/aux/broccoli/test/broccoli-v6addrs.bro "Communication::listen_ssl=T" "ssl_ca_certificate=../ca_cert.pem" "ssl_private_key=../bro.pem" +# @TEST-EXEC: btest-bg-run broccoli BROCCOLI_CONFIG_FILE=../broccoli.conf $BUILD/aux/broccoli/test/broccoli-v6addrs +# @TEST-EXEC: btest-bg-wait -k 20 +# @TEST-EXEC: btest-diff bro/.stdout +# @TEST-EXEC: btest-diff broccoli/.stdout + +@TEST-START-FILE broccoli.conf +/broccoli/use_ssl yes +/broccoli/ca_cert ../ca_cert.pem +/broccoli/host_cert ../bro.pem +/broccoli/host_key ../bro.pem +@TEST-END-FILE + +@TEST-START-FILE bro.pem +-----BEGIN RSA PRIVATE KEY----- +MIICXgIBAAKBgQD17FE8UVaO224Y8UL2bH1okCYxr5dVytTQ93uE5J9caGADzPZe +qYPuvtPt9ivhBtf2L9odK7unQU60v6RsO3bb9bQktQbEdh0FEjnso2UHe/nLreYn +VyLCEp9Sh1OFQnMhJNYuzNwVzWOqH/TYNy3ODueZTS4YBsRyEkpEfgeoaQIDAQAB +AoGAJ/S1Xi94+Mz+Hl9UmeUWmx6QlhIJbI7/9NPA5d6fZcwvjW6HuOmh3fBzTn5o +sq8B96Xesk6gtpQNzaA1fsBKlzDSpGRDVg2odN9vIT3jd0Dub2F47JHdFCqtMUIV +rCsO+fpGtavv1zJ/rzlJz7rx4cRP+/Gwd5YlH0q5cFuHhAECQQD9q328Ye4A7o2e +cLOhzuWUZszqdIY7ZTgDtk06F57VrjLVERrZjrtAwbs77m+ybw4pDKKU7H5inhQQ +03PU40ARAkEA+C6cCM6E4hRwuR+QyIqpNC4CzgPaKlF+VONZLYYvHEwFvx2/EPtX +zOZdE4HdJwnXBYx7+AGFeq8uHhrN2Tq62QJBAMory2JAinejqKsGF6R2SPMlm1ug +0vqziRksShBqkuSqmUjHASczYnoR7S+usMb9S8PblhgrA++FHWjrnf2lwIECQQCj ++/AfpY2J8GWW/HNm/q/UiX5S75qskZI+tsXK3bmtIdI+OIJxzxFxktj3NbyRud+4 +i92xvhebO7rmK2HOYg7pAkEA2wrwY1E237twoYXuUInv9F9kShKLQs19nup/dfmF +xfoVqYjJwidzPfgngowJZij7SoTaIBKv/fKp5Tq6xW3AEg== +-----END RSA PRIVATE KEY----- +-----BEGIN CERTIFICATE----- +MIICZDCCAc2gAwIBAgIJAKoxR9yFGsk8MA0GCSqGSIb3DQEBBQUAMCsxKTAnBgNV +BAMTIEJybyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MCAXDTExMDYxNTIx +MjgxNVoYDzIxMTEwNTIyMjEyODE1WjArMSkwJwYDVQQDEyBCcm8gUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +9exRPFFWjttuGPFC9mx9aJAmMa+XVcrU0Pd7hOSfXGhgA8z2XqmD7r7T7fYr4QbX +9i/aHSu7p0FOtL+kbDt22/W0JLUGxHYdBRI57KNlB3v5y63mJ1ciwhKfUodThUJz +ISTWLszcFc1jqh/02Dctzg7nmU0uGAbEchJKRH4HqGkCAwEAAaOBjTCBijAdBgNV +HQ4EFgQU2vIsKYuGhHP8c7GeJLfWAjbKCFgwWwYDVR0jBFQwUoAU2vIsKYuGhHP8 +c7GeJLfWAjbKCFihL6QtMCsxKTAnBgNVBAMTIEJybyBSb290IENlcnRpZmljYXRp +b24gQXV0aG9yaXR5ggkAqjFH3IUayTwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQUFAAOBgQAF2oceL61dA7WxA9lxcxsA/Fccr7+J6sO+pLXoZtx5tpknEuIUebkm +UfMGAiyYIenHi8u0Sia8KrIfuCDc2dG3DYmfX7/faCEbtSx8KtNQFIs3aXr1zhsw +3sX9fLS0gp/qHoPMuhbhlvTlMFSE/Mih3KDsZEGcifzI6ooLF0YP5A== +-----END CERTIFICATE----- +@TEST-END-FILE + +@TEST-START-FILE ca_cert.pem +-----BEGIN CERTIFICATE----- +MIICZDCCAc2gAwIBAgIJAKoxR9yFGsk8MA0GCSqGSIb3DQEBBQUAMCsxKTAnBgNV +BAMTIEJybyBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MCAXDTExMDYxNTIx +MjgxNVoYDzIxMTEwNTIyMjEyODE1WjArMSkwJwYDVQQDEyBCcm8gUm9vdCBDZXJ0 +aWZpY2F0aW9uIEF1dGhvcml0eTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA +9exRPFFWjttuGPFC9mx9aJAmMa+XVcrU0Pd7hOSfXGhgA8z2XqmD7r7T7fYr4QbX +9i/aHSu7p0FOtL+kbDt22/W0JLUGxHYdBRI57KNlB3v5y63mJ1ciwhKfUodThUJz +ISTWLszcFc1jqh/02Dctzg7nmU0uGAbEchJKRH4HqGkCAwEAAaOBjTCBijAdBgNV +HQ4EFgQU2vIsKYuGhHP8c7GeJLfWAjbKCFgwWwYDVR0jBFQwUoAU2vIsKYuGhHP8 +c7GeJLfWAjbKCFihL6QtMCsxKTAnBgNVBAMTIEJybyBSb290IENlcnRpZmljYXRp +b24gQXV0aG9yaXR5ggkAqjFH3IUayTwwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0B +AQUFAAOBgQAF2oceL61dA7WxA9lxcxsA/Fccr7+J6sO+pLXoZtx5tpknEuIUebkm +UfMGAiyYIenHi8u0Sia8KrIfuCDc2dG3DYmfX7/faCEbtSx8KtNQFIs3aXr1zhsw +3sX9fLS0gp/qHoPMuhbhlvTlMFSE/Mih3KDsZEGcifzI6ooLF0YP5A== +-----END CERTIFICATE----- +@TEST-END-FILE From 74f3a32321010928cf380abec3df30640382b289 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Thu, 17 May 2012 12:59:20 -0500 Subject: [PATCH 05/15] Enable Bro to communicate with peers over non-global IPv6 addresses. This usually requires specifying an additional zone identifier (see RFC 4007). The connect() and listen() BIFs have been changed to accept this zone identifier as an argument. --- scripts/base/frameworks/cluster/main.bro | 3 + .../frameworks/cluster/setup-connections.bro | 25 ++- .../base/frameworks/communication/main.bro | 16 +- scripts/base/frameworks/control/main.bro | 4 + .../frameworks/communication/listen.bro | 2 +- .../policy/frameworks/control/controller.bro | 4 +- src/RemoteSerializer.cc | 197 +++++++++++++----- src/RemoteSerializer.h | 18 +- src/bro.bif | 19 +- src/util.cc | 2 + 10 files changed, 215 insertions(+), 75 deletions(-) diff --git a/scripts/base/frameworks/cluster/main.bro b/scripts/base/frameworks/cluster/main.bro index 1e89e9b2a7..766dea912f 100644 --- a/scripts/base/frameworks/cluster/main.bro +++ b/scripts/base/frameworks/cluster/main.bro @@ -77,6 +77,9 @@ export { node_type: NodeType; ## The IP address of the cluster node. ip: addr; + ## If the *ip* field is a non-global IPv6 address, this field + ## can specify a particular :rfc:`4007` ``zone_id``. + zone_id: string &default=""; ## The port to which the this local node can connect when ## establishing communication. p: port; diff --git a/scripts/base/frameworks/cluster/setup-connections.bro b/scripts/base/frameworks/cluster/setup-connections.bro index b5a0d25e1f..3d89e39f30 100644 --- a/scripts/base/frameworks/cluster/setup-connections.bro +++ b/scripts/base/frameworks/cluster/setup-connections.bro @@ -19,23 +19,26 @@ event bro_init() &priority=9 # Connections from the control node for runtime control and update events. # Every node in a cluster is eligible for control from this host. if ( n$node_type == CONTROL ) - Communication::nodes["control"] = [$host=n$ip, $connect=F, - $class="control", $events=control_events]; + Communication::nodes["control"] = [$host=n$ip, $zone_id=n$zone_id, + $connect=F, $class="control", + $events=control_events]; if ( me$node_type == MANAGER ) { if ( n$node_type == WORKER && n$manager == node ) Communication::nodes[i] = - [$host=n$ip, $connect=F, + [$host=n$ip, $zone_id=n$zone_id, $connect=F, $class=i, $events=worker2manager_events, $request_logs=T]; if ( n$node_type == PROXY && n$manager == node ) Communication::nodes[i] = - [$host=n$ip, $connect=F, + [$host=n$ip, $zone_id=n$zone_id, $connect=F, $class=i, $events=proxy2manager_events, $request_logs=T]; if ( n$node_type == TIME_MACHINE && me?$time_machine && me$time_machine == i ) - Communication::nodes["time-machine"] = [$host=nodes[i]$ip, $p=nodes[i]$p, + Communication::nodes["time-machine"] = [$host=nodes[i]$ip, + $zone_id=nodes[i]$zone_id, + $p=nodes[i]$p, $connect=T, $retry=1min, $events=tm2manager_events]; } @@ -44,7 +47,8 @@ event bro_init() &priority=9 { if ( n$node_type == WORKER && n$proxy == node ) Communication::nodes[i] = - [$host=n$ip, $connect=F, $class=i, $sync=T, $auth=T, $events=worker2proxy_events]; + [$host=n$ip, $zone_id=n$zone_id, $connect=F, $class=i, + $sync=T, $auth=T, $events=worker2proxy_events]; # accepts connections from the previous one. # (This is not ideal for setups with many proxies) @@ -53,16 +57,18 @@ event bro_init() &priority=9 { if ( n?$proxy ) Communication::nodes[i] - = [$host=n$ip, $p=n$p, + = [$host=n$ip, $zone_id=n$zone_id, $p=n$p, $connect=T, $auth=F, $sync=T, $retry=1mins]; else if ( me?$proxy && me$proxy == i ) Communication::nodes[me$proxy] - = [$host=nodes[i]$ip, $connect=F, $auth=T, $sync=T]; + = [$host=nodes[i]$ip, $zone_id=nodes[i]$zone_id, + $connect=F, $auth=T, $sync=T]; } # Finally the manager, to send it status updates. if ( n$node_type == MANAGER && me$manager == i ) Communication::nodes["manager"] = [$host=nodes[i]$ip, + $zone_id=nodes[i]$zone_id, $p=nodes[i]$p, $connect=T, $retry=1mins, $class=node, @@ -72,6 +78,7 @@ event bro_init() &priority=9 { if ( n$node_type == MANAGER && me$manager == i ) Communication::nodes["manager"] = [$host=nodes[i]$ip, + $zone_id=nodes[i]$zone_id, $p=nodes[i]$p, $connect=T, $retry=1mins, $class=node, @@ -79,6 +86,7 @@ event bro_init() &priority=9 if ( n$node_type == PROXY && me$proxy == i ) Communication::nodes["proxy"] = [$host=nodes[i]$ip, + $zone_id=nodes[i]$zone_id, $p=nodes[i]$p, $connect=T, $retry=1mins, $sync=T, $class=node, @@ -87,6 +95,7 @@ event bro_init() &priority=9 if ( n$node_type == TIME_MACHINE && me?$time_machine && me$time_machine == i ) Communication::nodes["time-machine"] = [$host=nodes[i]$ip, + $zone_id=nodes[i]$zone_id, $p=nodes[i]$p, $connect=T, $retry=1min, diff --git a/scripts/base/frameworks/communication/main.bro b/scripts/base/frameworks/communication/main.bro index 26ec9f41b8..b9b15bfd22 100644 --- a/scripts/base/frameworks/communication/main.bro +++ b/scripts/base/frameworks/communication/main.bro @@ -23,9 +23,14 @@ export { ## Defines if a listening socket can bind to IPv6 addresses. const listen_ipv6 = F &redef; + ## If :bro:id:`Communication::listen_interface` is a non-global + ## IPv6 address and requires a specific :rfc:`4007` ``zone_id``, + ## it can be specified here. + const listen_ipv6_zone_id = "" &redef; + ## Defines the interval at which to retry binding to - ## :bro:id:`listen_interface` on :bro:id:`listen_port` if it's already in - ## use. + ## :bro:id:`Communication::listen_interface` on + ## :bro:id:`Communication::listen_port` if it's already in use. const listen_retry = 30 secs &redef; ## Default compression level. Compression level is 0-9, with 0 = no @@ -60,6 +65,10 @@ export { type Node: record { ## Remote address. host: addr; + + ## If the *host* field is a non-global IPv6 address, this field + ## can specify a particular :rfc:`4007` ``zone_id``. + zone_id: string &optional; ## Port of the remote Bro communication endpoint if we are initiating ## the connection based on the :bro:id:`connect` field. @@ -187,7 +196,8 @@ function connect_peer(peer: string) p = node$p; local class = node?$class ? node$class : ""; - local id = connect(node$host, p, class, node$retry, node$ssl); + local zone_id = node?$zone_id ? node$zone_id : ""; + local id = connect(node$host, zone_id, p, class, node$retry, node$ssl); if ( id == PEER_ID_NONE ) Log::write(Communication::LOG, [$ts = network_time(), diff --git a/scripts/base/frameworks/control/main.bro b/scripts/base/frameworks/control/main.bro index 4fe8872801..63e5f639a0 100644 --- a/scripts/base/frameworks/control/main.bro +++ b/scripts/base/frameworks/control/main.bro @@ -11,6 +11,10 @@ export { ## The port of the host that will be controlled. const host_port = 0/tcp &redef; + ## If :bro:id:`Control::host` is a non-global IPv6 address and + ## requires a specific :rfc:`4007` ``zone_id``, it can be set here. + const zone_id = "" &redef; + ## The command that is being done. It's typically set on the ## command line. const cmd = "" &redef; diff --git a/scripts/policy/frameworks/communication/listen.bro b/scripts/policy/frameworks/communication/listen.bro index 609e8c91d6..111bc64a23 100644 --- a/scripts/policy/frameworks/communication/listen.bro +++ b/scripts/policy/frameworks/communication/listen.bro @@ -9,5 +9,5 @@ event bro_init() &priority=-10 { enable_communication(); listen(listen_interface, listen_port, listen_ssl, listen_ipv6, - listen_retry); + listen_ipv6_zone_id, listen_retry); } diff --git a/scripts/policy/frameworks/control/controller.bro b/scripts/policy/frameworks/control/controller.bro index 39647095db..22b19bf973 100644 --- a/scripts/policy/frameworks/control/controller.bro +++ b/scripts/policy/frameworks/control/controller.bro @@ -25,8 +25,8 @@ event bro_init() &priority=5 # Establish the communication configuration and only request response # messages. - Communication::nodes["control"] = [$host=host, $p=host_port, - $sync=F, $connect=T, + Communication::nodes["control"] = [$host=host, $zone_id=zone_id, + $p=host_port, $sync=F, $connect=T, $class="control", $events=Control::controllee_events]; } diff --git a/src/RemoteSerializer.cc b/src/RemoteSerializer.cc index 9123e99ef4..b73494204c 100644 --- a/src/RemoteSerializer.cc +++ b/src/RemoteSerializer.cc @@ -173,6 +173,9 @@ #include #include +#include +#include +#include #include "RemoteSerializer.h" #include "Func.h" @@ -323,6 +326,16 @@ static const char* msgToStr(int msg) } } +static vector tokenize(const string& s, char delim) + { + vector tokens; + stringstream ss(s); + string token; + while ( std::getline(ss, token, delim) ) + tokens.push_back(token); + return tokens; + } + // Start of every message between two processes. We do the low-level work // ourselves to make this 64-bit safe. (The actual layout is an artifact of // an earlier design that depended on how a 32-bit GCC lays out its structs ...) @@ -665,7 +678,8 @@ void RemoteSerializer::Fork() } RemoteSerializer::PeerID RemoteSerializer::Connect(const IPAddr& ip, - uint16 port, const char* our_class, double retry, bool use_ssl) + const string& zone_id, uint16 port, const char* our_class, double retry, + bool use_ssl) { if ( ! using_communication ) return true; @@ -682,11 +696,13 @@ RemoteSerializer::PeerID RemoteSerializer::Connect(const IPAddr& ip, if ( our_class ) p->our_class = our_class; - uint32 bytes[4]; - ip.CopyIPv6(bytes, IPAddr::Host); + const size_t BUFSIZE = 1024; + char* data = new char[BUFSIZE]; + snprintf(data, BUFSIZE, "%"PRIu64",%s,%s,%"PRIu16",%"PRIu32",%d", p->id, + ip.AsString().c_str(), zone_id.c_str(), port, uint32(retry), + use_ssl); - if ( ! SendToChild(MSG_CONNECT_TO, p, 8, p->id, bytes[0], bytes[1], - bytes[2], bytes[3], port, uint32(retry), use_ssl) ) + if ( ! SendToChild(MSG_CONNECT_TO, p, data) ) { RemovePeer(p); return false; @@ -1219,7 +1235,7 @@ bool RemoteSerializer::SendCapabilities(Peer* peer) } bool RemoteSerializer::Listen(const IPAddr& ip, uint16 port, bool expect_ssl, - bool ipv6, double retry) + bool ipv6, const string& zone_id, double retry) { if ( ! using_communication ) return true; @@ -1229,13 +1245,16 @@ bool RemoteSerializer::Listen(const IPAddr& ip, uint16 port, bool expect_ssl, if ( ! ipv6 && ip.GetFamily() == IPv6 && ip != IPAddr("0.0.0.0") && ip != IPAddr("::") ) - reporter->FatalError("Attempt to listen on address %s, but IPv6 communication disabled", ip.AsString().c_str()); + reporter->FatalError("Attempt to listen on address %s, but IPv6 " + "communication disabled", ip.AsString().c_str()); - uint32 bytes[4]; - ip.CopyIPv6(bytes, IPAddr::Host); + const size_t BUFSIZE = 1024; + char* data = new char[BUFSIZE]; + snprintf(data, BUFSIZE, "%s,%"PRIu16",%d,%d,%s,%"PRIu32, + ip.AsString().c_str(), port, expect_ssl, ipv6, zone_id.c_str(), + (uint32) retry); - if ( ! SendToChild(MSG_LISTEN, 0, 8, bytes[0], bytes[1], bytes[2], bytes[3], - port, expect_ssl, ipv6, (uint32) retry) ) + if ( ! SendToChild(MSG_LISTEN, 0, data) ) return false; listening = true; @@ -1947,9 +1966,22 @@ bool RemoteSerializer::EnterPhaseRunning(Peer* peer) bool RemoteSerializer::ProcessConnected() { // IP and port follow. - uint32* args = (uint32*) current_args->data; - IPAddr host = IPAddr(IPv6, args, IPAddr::Network); - uint16 port = (uint16) ntohl(args[4]); + vector args = tokenize(current_args->data, ','); + + if ( args.size() != 2 ) + { + InternalCommError("ProcessConnected() bad number of arguments"); + return false; + } + + IPAddr host = IPAddr(args[0]); + uint16 port; + + if ( ! atoi_n(args[1].size(), args[1].c_str(), 0, 10, port) ) + { + InternalCommError("ProcessConnected() bad peer port string"); + return false; + } if ( ! current_peer ) { @@ -3692,14 +3724,43 @@ bool SocketComm::ForwardChunkToPeer() bool SocketComm::ProcessConnectTo() { assert(parent_args); - uint32* args = (uint32*) parent_args->data; + vector args = tokenize(parent_args->data, ','); + + if ( args.size() != 6 ) + { + Error(fmt("ProcessConnectTo() bad number of arguments")); + return false; + } Peer* peer = new Peer; - peer->id = ntohl(args[0]); - peer->ip = IPAddr(IPv6, &args[1], IPAddr::Network); - peer->port = ntohl(args[5]); - peer->retry = ntohl(args[6]); - peer->ssl = ntohl(args[7]); + + if ( ! atoi_n(args[0].size(), args[0].c_str(), 0, 10, peer->id) ) + { + Error(fmt("ProccessConnectTo() bad peer id string")); + delete peer; + return false; + } + + peer->ip = IPAddr(args[1]); + peer->zone_id = args[2]; + + if ( ! atoi_n(args[3].size(), args[3].c_str(), 0, 10, peer->port) ) + { + Error(fmt("ProcessConnectTo() bad peer port string")); + delete peer; + return false; + } + + if ( ! atoi_n(args[4].size(), args[4].c_str(), 0, 10, peer->retry) ) + { + Error(fmt("ProcessConnectTo() bad peer retry string")); + delete peer; + return false; + } + + peer->ssl = false; + if ( args[5] != "0" ) + peer->ssl = true; return Connect(peer); } @@ -3707,13 +3768,37 @@ bool SocketComm::ProcessConnectTo() bool SocketComm::ProcessListen() { assert(parent_args); - uint32* args = (uint32*) parent_args->data; + vector args = tokenize(parent_args->data, ','); - listen_if = IPAddr(IPv6, args, IPAddr::Network); - listen_port = uint16(ntohl(args[4])); - listen_ssl = ntohl(args[5]) != 0; - enable_ipv6 = ntohl(args[6]) != 0; - bind_retry_interval = ntohl(args[7]); + if ( args.size() != 6 ) + { + Error(fmt("ProcessListen() bad number of arguments")); + return false; + } + + listen_if = args[0]; + + if ( ! atoi_n(args[1].size(), args[1].c_str(), 0, 10, listen_port) ) + { + Error(fmt("ProcessListen() bad peer port string")); + return false; + } + + listen_ssl = false; + if ( args[2] != "0" ) + listen_ssl = true; + + enable_ipv6 = false; + if ( args[3] != "0" ) + enable_ipv6 = true; + + listen_zone_id = args[4]; + + if ( ! atoi_n(args[5].size(), args[5].c_str(), 0, 10, bind_retry_interval) ) + { + Error(fmt("ProcessListen() bad peer port string")); + return false; + } return Listen(); } @@ -3889,10 +3974,11 @@ bool SocketComm::Connect(Peer* peer) char port_str[16]; modp_uitoa10(peer->port, port_str); - // TODO: better to accept string arguments from the user to pass into - // getaddrinfo? This might make it easier to explicitly connect to - // non-global IPv6 addresses with a scope zone identifier (RFC 4007). - status = getaddrinfo(peer->ip.AsString().c_str(), port_str, &hints, &res0); + string gaihostname(peer->ip.AsString()); + if ( peer->zone_id != "" ) + gaihostname.append("%").append(peer->zone_id); + + status = getaddrinfo(gaihostname.c_str(), port_str, &hints, &res0); if ( status != 0 ) { Error(fmt("getaddrinfo error: %s", gai_strerror(status))); @@ -3964,11 +4050,12 @@ bool SocketComm::Connect(Peer* peer) { Log("connected", peer); - uint32 bytes[4]; - peer->ip.CopyIPv6(bytes, IPAddr::Host); + const size_t BUFSIZE = 1024; + char* data = new char[BUFSIZE]; + snprintf(data, BUFSIZE, "%s,%"PRIu32, peer->ip.AsString().c_str(), + peer->port); - if ( ! SendToParent(MSG_CONNECTED, peer, 5, bytes[0], bytes[1], - bytes[2], bytes[3], peer->port) ) + if ( ! SendToParent(MSG_CONNECTED, peer, data) ) return false; } @@ -4011,12 +4098,14 @@ bool SocketComm::Listen() addrinfo hints, *res, *res0; bzero(&hints, sizeof(hints)); + IPAddr listen_ip(listen_if); + if ( enable_ipv6 ) { - if ( listen_if == IPAddr("0.0.0.0") || listen_if == IPAddr("::") ) + if ( listen_ip == IPAddr("0.0.0.0") || listen_ip == IPAddr("::") ) hints.ai_family = PF_UNSPEC; else - hints.ai_family = listen_if.GetFamily() == IPv4 ? PF_INET : PF_INET6; + hints.ai_family = listen_ip.GetFamily() == IPv4 ? PF_INET : PF_INET6; } else hints.ai_family = PF_INET; @@ -4028,15 +4117,15 @@ bool SocketComm::Listen() char port_str[16]; modp_uitoa10(listen_port, port_str); + string scoped_addr(listen_if); + if ( listen_zone_id != "" ) + scoped_addr.append("%").append(listen_zone_id); const char* addr_str = 0; - if ( listen_if != IPAddr("0.0.0.0") && listen_if != IPAddr("::") ) - addr_str = listen_if.AsString().c_str(); + if ( listen_ip != IPAddr("0.0.0.0") && listen_ip != IPAddr("::") ) + addr_str = scoped_addr.c_str(); CloseListenFDs(); - // TODO: better to accept string arguments from the user to pass into - // getaddrinfo? This might make it easier to explicitly bind to a - // non-global IPv6 address with a scope zone identifier (RFC 4007). if ( (status = getaddrinfo(addr_str, port_str, &hints, &res0)) != 0 ) { Error(fmt("getaddrinfo error: %s", gai_strerror(status))); @@ -4056,6 +4145,10 @@ bool SocketComm::Listen() IPAddr(((sockaddr_in*)res->ai_addr)->sin_addr) : IPAddr(((sockaddr_in6*)res->ai_addr)->sin6_addr); + string l_addr_str(a.AsURIString()); + if ( listen_zone_id != "") + l_addr_str.append("%").append(listen_zone_id); + int fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol); if ( fd < 0 ) { @@ -4075,7 +4168,7 @@ bool SocketComm::Listen() if ( bind(fd, res->ai_addr, res->ai_addrlen) < 0 ) { - Error(fmt("can't bind to %s:%s, %s", a.AsURIString().c_str(), + Error(fmt("can't bind to %s:%s, %s", l_addr_str.c_str(), port_str, strerror(errno))); close(fd); @@ -4092,14 +4185,14 @@ bool SocketComm::Listen() if ( listen(fd, 50) < 0 ) { - Error(fmt("can't listen on %s:%s, %s", a.AsURIString().c_str(), + Error(fmt("can't listen on %s:%s, %s", l_addr_str.c_str(), port_str, strerror(errno))); close(fd); continue; } listen_fds.push_back(fd); - Log(fmt("listening on %s:%s (%s)", a.AsURIString().c_str(), port_str, + Log(fmt("listening on %s:%s (%s)", l_addr_str.c_str(), port_str, listen_ssl ? "ssl" : "clear")); } @@ -4155,11 +4248,12 @@ bool SocketComm::AcceptConnection(int fd) Log(fmt("accepted %s connection", peer->ssl ? "SSL" : "clear"), peer); - uint32 bytes[4]; - peer->ip.CopyIPv6(bytes, IPAddr::Host); + const size_t BUFSIZE = 1024; + char* data = new char[BUFSIZE]; + snprintf(data, BUFSIZE, "%s,%"PRIu32, peer->ip.AsString().c_str(), + peer->port); - if ( ! SendToParent(MSG_CONNECTED, peer, 5, bytes[0], bytes[1], bytes[2], - bytes[3], peer->port) ) + if ( ! SendToParent(MSG_CONNECTED, peer, data) ) return false; return true; @@ -4176,8 +4270,13 @@ const char* SocketComm::MakeLogString(const char* msg, Peer* peer) int len = 0; if ( peer ) + { + string scoped_addr(peer->ip.AsURIString()); + if ( peer->zone_id != "" ) + scoped_addr.append("%").append(peer->zone_id); len = snprintf(buffer, BUFSIZE, "[#%d/%s:%d] ", int(peer->id), - peer->ip.AsURIString().c_str(), peer->port); + scoped_addr.c_str(), peer->port); + } len += safe_snprintf(buffer + len, BUFSIZE - len, "%s", msg); return buffer; diff --git a/src/RemoteSerializer.h b/src/RemoteSerializer.h index f6f94f53d3..4ebf15e68d 100644 --- a/src/RemoteSerializer.h +++ b/src/RemoteSerializer.h @@ -11,6 +11,7 @@ #include "File.h" #include +#include class IncrementalSendTimer; @@ -34,7 +35,8 @@ public: static const PeerID PEER_NONE = SOURCE_LOCAL; // Connect to host (returns PEER_NONE on error). - PeerID Connect(const IPAddr& ip, uint16 port, const char* our_class, double retry, bool use_ssl); + PeerID Connect(const IPAddr& ip, const string& zone_id, uint16 port, + const char* our_class, double retry, bool use_ssl); // Close connection to host. bool CloseConnection(PeerID peer); @@ -63,7 +65,7 @@ public: // Start to listen. bool Listen(const IPAddr& ip, uint16 port, bool expect_ssl, bool ipv6, - double retry); + const string& zone_id, double retry); // Stop it. bool StopListening(); @@ -422,6 +424,7 @@ protected: RemoteSerializer::PeerID id; ChunkedIO* io; IPAddr ip; + string zone_id; uint16 port; char state; bool connected; @@ -502,12 +505,13 @@ protected: // If the port we're trying to bind to is already in use, we will retry // it regularly. - IPAddr listen_if; + string listen_if; + string listen_zone_id; // RFC 4007 IPv6 zone_id uint16 listen_port; - bool listen_ssl; - bool enable_ipv6; // allow IPv6 listen sockets - uint32 bind_retry_interval; - time_t listen_next_try; + bool listen_ssl; // use SSL for IO + bool enable_ipv6; // allow IPv6 listen sockets + uint32 bind_retry_interval; // retry interval for already-in-use sockets + time_t listen_next_try; // time at which to try another bind bool shutting_conns_down; bool terminating; bool killing; diff --git a/src/bro.bif b/src/bro.bif index 3f4215dc13..f1e451bb03 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -5267,6 +5267,10 @@ function capture_state_updates%(filename: string%) : bool ## ## ip: The IP address of the remote peer. ## +## zone_id: If *ip* is a non-global IPv6 address, a particular :rfc:`4007` +## ``zone_id`` can given here. An empty string, ``""``, means +## not to add any ``zone_id``. +## ## port: The port of the remote peer. ## ## our_class: If an non-empty string, the remote (listening) peer checks it @@ -5290,10 +5294,11 @@ function capture_state_updates%(filename: string%) : bool ## set_compression_level ## send_state ## send_id -function connect%(ip: addr, p: port, our_class: string, retry: interval, ssl: bool%) : count +function connect%(ip: addr, zone_id: string, p: port, our_class: string, retry: interval, ssl: bool%) : count %{ - return new Val(uint32(remote_serializer->Connect(ip->AsAddr(), p->Port(), - our_class->CheckString(), retry, ssl)), + return new Val(uint32(remote_serializer->Connect(ip->AsAddr(), + zone_id->CheckString(), p->Port(), our_class->CheckString(), + retry, ssl)), TYPE_COUNT); %} @@ -5404,15 +5409,19 @@ function set_compression_level%(p: event_peer, level: count%) : bool ## ## ipv6: If true, enable listening on IPv6 addresses. ## +## zone_id: If *ip* is a non-global IPv6 address, a particular :rfc:`4007` +## ``zone_id`` can given here. An empty string, ``""``, means +## not to add any ``zone_id``. +## ## retry_interval: If address *ip* is found to be already in use, this is ## the interval at which to automatically retry binding. ## ## Returns: True on success. ## ## .. bro:see:: connect disconnect -function listen%(ip: addr, p: port, ssl: bool, ipv6: bool, retry_interval: interval%) : bool +function listen%(ip: addr, p: port, ssl: bool, ipv6: bool, zone_id: string, retry_interval: interval%) : bool %{ - return new Val(remote_serializer->Listen(ip->AsAddr(), p->Port(), ssl, ipv6, retry_interval), TYPE_BOOL); + return new Val(remote_serializer->Listen(ip->AsAddr(), p->Port(), ssl, ipv6, zone_id->CheckString(), retry_interval), TYPE_BOOL); %} ## Checks whether the last raised event came from a remote peer. diff --git a/src/util.cc b/src/util.cc index 90143923f1..798be400d1 100644 --- a/src/util.cc +++ b/src/util.cc @@ -376,6 +376,8 @@ template int atoi_n(int len, const char* s, const char** end, int base, // Instantiate the ones we need. template int atoi_n(int len, const char* s, const char** end, int base, int& result); +template int atoi_n(int len, const char* s, const char** end, int base, uint16_t& result); +template int atoi_n(int len, const char* s, const char** end, int base, uint32_t& result); template int atoi_n(int len, const char* s, const char** end, int base, int64_t& result); template int atoi_n(int len, const char* s, const char** end, int base, uint64_t& result); From be65ddca375e906bd6d409d50fbe894c759bb32d Mon Sep 17 00:00:00 2001 From: Daniel Thayer Date: Thu, 17 May 2012 16:03:17 -0500 Subject: [PATCH 06/15] Correct various errors in the BIF documentation --- src/bro.bif | 210 ++++++++++++++++++++++++------------------------ src/strings.bif | 50 ++++++------ 2 files changed, 131 insertions(+), 129 deletions(-) diff --git a/src/bro.bif b/src/bro.bif index 15740a83c7..212a27044f 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -963,7 +963,7 @@ function sha256_hash_finish%(index: any%): string ## Generates a random number. ## -## max: The maximum value the random number. +## max: The maximum value of the random number. ## ## Returns: a random positive integer in the interval *[0, max)*. ## @@ -1020,7 +1020,7 @@ extern "C" { ## data: The data to find the MIME type for. ## ## return_mime: If true, the function returns a short MIME type string (e.g., -## ``text/plain`` instead of a more elaborate textual description. +## ``text/plain`` instead of a more elaborate textual description). ## ## Returns: The MIME type of *data*. function identify_data%(data: string, return_mime: bool%): string @@ -1241,8 +1241,6 @@ function unique_id_from%(pool: int, prefix: string%) : string ## Removes all elements from a set or table. ## ## v: The set or table -## -## Returns: The cleared set/table or 0 if *v* is not a set/table type. function clear_table%(v: any%): any %{ if ( v->Type()->Tag() == TYPE_TABLE ) @@ -1290,7 +1288,7 @@ function same_object%(o1: any, o2: any%): bool return new Val(o1 == o2, TYPE_BOOL); %} -## Returns the number bytes that a value occupies in memory. +## Returns the number of bytes that a value occupies in memory. ## ## v: The value ## @@ -1306,7 +1304,7 @@ function val_size%(v: any%): count ## ## newsize: The new size of *aggr*. ## -## Returns: The old size of *aggr* and 0 if *aggr* is not a :bro:type:`vector`. +## Returns: The old size of *aggr*, or 0 if *aggr* is not a :bro:type:`vector`. function resize%(aggr: any, newsize: count%) : count %{ if ( aggr->Type()->Tag() != TYPE_VECTOR ) @@ -1423,7 +1421,7 @@ bool indirect_int_sort_function(int a, int b) %%} ## Sorts a vector in place. The second argument is a comparison function that -## takes two arguments: if the vector type is \verb|vector of T|, then the +## takes two arguments: if the vector type is ``vector of T``, then the ## comparison function must be ``function(a: T, b: T): bool``, which returns ## ``a < b`` for some type-specific notion of the less-than operator. ## @@ -1599,7 +1597,7 @@ function cat%(...%): string ## given argument. If any of the variable arguments is an empty string it is ## replaced by a given default string instead. ## -## sep: The separator to place betwen each argument. +## sep: The separator to place between each argument. ## ## def: The default string to use when an argument is the empty string. ## @@ -1657,7 +1655,7 @@ function cat_sep%(sep: string, def: string, ...%): string ## ## - ``[DT]``: ISO timestamp with microsecond precision ## -## - ``d``: Signed/Unsigned integer (using C-style ``%lld|``/``%llu`` +## - ``d``: Signed/Unsigned integer (using C-style ``%lld``/``%llu`` ## for ``int``/``count``) ## ## - ``x``: Unsigned hexadecimal (using C-style ``%llx``); @@ -1782,7 +1780,7 @@ function log10%(d: double%): double # =========================================================================== ## Determines whether *c* has been received externally. For example, -## Broccoli or the Time Machine can send packets to Bro via a mechanism that +## Broccoli or the Time Machine can send packets to Bro via a mechanism that is ## one step lower than sending events. This function checks whether the packets ## of a connection stem from one of these external *packet sources*. ## @@ -1796,7 +1794,7 @@ function is_external_connection%(c: connection%) : bool ## Returns the ID of the analyzer which raised the current event. ## -## Returns: The ID of the analyzer which raised hte current event, or 0 if +## Returns: The ID of the analyzer which raised the current event, or 0 if ## none. function current_analyzer%(%) : count %{ @@ -2053,7 +2051,7 @@ function get_gap_summary%(%): gap_info %} ## Generates a table of the size of all global variables. The table index is -## the variable name and the value the variable size in bytes. +## the variable name and the value is the variable size in bytes. ## ## Returns: A table that maps variable names to their sizes. ## @@ -2138,7 +2136,7 @@ function lookup_ID%(id: string%) : any return i->ID_Val()->Ref(); %} -## Generates meta data about a record fields. The returned information +## Generates metadata about a record's fields. The returned information ## includes the field name, whether it is logged, its value (if it has one), ## and its default value (if specified). ## @@ -2269,11 +2267,11 @@ function dump_rule_stats%(f: file%): bool return new Val(1, TYPE_BOOL); %} -## Checks wheter Bro is terminating. +## Checks if Bro is terminating. ## ## Returns: True if Bro is in the process of shutting down. ## -## .. bro:see: terminate +## .. bro:see:: terminate function bro_is_terminating%(%): bool %{ return new Val(terminating, TYPE_BOOL); @@ -2354,7 +2352,7 @@ function routing0_data_to_addrs%(s: string%): addr_vec return rval; %} -## Converts a :bro:type:`addr` to a :bro:type:`index_vec`. +## Converts an :bro:type:`addr` to an :bro:type:`index_vec`. ## ## a: The address to convert into a vector of counts. ## @@ -2374,7 +2372,7 @@ function addr_to_counts%(a: addr%): index_vec return rval; %} -## Converts a :bro:type:`index_vec` to a :bro:type:`addr`. +## Converts an :bro:type:`index_vec` to an :bro:type:`addr`. ## ## v: The vector containing host-order IP address representation, ## one element for IPv4 addresses, four elements for IPv6 addresses. @@ -2404,7 +2402,7 @@ function counts_to_addr%(v: index_vec%): addr } %} -## Converts a :bro:type:`string` to a :bro:type:`int`. +## Converts a :bro:type:`string` to an :bro:type:`int`. ## ## str: The :bro:type:`string` to convert. ## @@ -2434,7 +2432,7 @@ function to_int%(str: string%): int ## ## n: The :bro:type:`int` to convert. ## -## Returns: The :bro:type:`int` *n* as unsigned integer or 0 if *n* < 0. +## Returns: The :bro:type:`int` *n* as unsigned integer, or 0 if *n* < 0. function int_to_count%(n: int%): count %{ if ( n < 0 ) @@ -2449,7 +2447,7 @@ function int_to_count%(n: int%): count ## ## d: The :bro:type:`double` to convert. ## -## Returns: The :bro:type:`double` *d* as unsigned integer or 0 if *d* < 0.0. +## Returns: The :bro:type:`double` *d* as unsigned integer, or 0 if *d* < 0.0. ## ## .. bro:see:: double_to_time function double_to_count%(d: double%): count @@ -2464,8 +2462,8 @@ function double_to_count%(d: double%): count ## ## str: The :bro:type:`string` to convert. ## -## Returns: The :bro:type:`string` *str* as unsigned integer or if in invalid -## format. +## Returns: The :bro:type:`string` *str* as unsigned integer, or 0 if *str* has +## an invalid format. ## ## .. bro:see:: to_addr to_int to_port to_subnet function to_count%(str: string%): count @@ -2498,7 +2496,7 @@ function interval_to_double%(i: interval%): double ## Converts a :bro:type:`time` value to a :bro:type:`double`. ## -## t: The :bro:type:`interval` to convert. +## t: The :bro:type:`time` to convert. ## ## Returns: The :bro:type:`time` value *t* as :bro:type:`double`. ## @@ -2508,11 +2506,11 @@ function time_to_double%(t: time%): double return new Val(t, TYPE_DOUBLE); %} -## Converts a :bro:type:`time` value to a :bro:type:`double`. +## Converts a :bro:type:`double` value to a :bro:type:`time`. ## -## t: The :bro:type:`interval` to convert. +## d: The :bro:type:`double` to convert. ## -## Returns: The :bro:type:`time` value *t* as :bro:type:`double`. +## Returns: The :bro:type:`double` value *d* as :bro:type:`time`. ## ## .. bro:see:: time_to_double double_to_count function double_to_time%(d: double%): time @@ -2550,7 +2548,7 @@ function port_to_count%(p: port%): count ## ## proto: The transport protocol. ## -## Returns: The :bro:type:`count` *c* as :bro:type:`port`. +## Returns: The :bro:type:`count` *num* as :bro:type:`port`. ## ## .. bro:see:: port_to_count function count_to_port%(num: count, proto: transport_proto%): port @@ -2562,7 +2560,7 @@ function count_to_port%(num: count, proto: transport_proto%): port ## ## ip: The :bro:type:`string` to convert. ## -## Returns: The :bro:type:`string` *ip* as :bro:type:`addr` or the unspecified +## Returns: The :bro:type:`string` *ip* as :bro:type:`addr`, or the unspecified ## address ``::`` if the input string does not parse correctly. ## ## .. bro:see:: to_count to_int to_port count_to_v4_addr raw_bytes_to_v4_addr @@ -2579,7 +2577,7 @@ function to_addr%(ip: string%): addr ## ## sn: The subnet to convert. ## -## Returns: The *sn* string as a :bro:type:`subnet` or the unspecified subnet +## Returns: The *sn* string as a :bro:type:`subnet`, or the unspecified subnet ## ``::/0`` if the input string does not parse correctly. ## ## .. bro:see:: to_count to_int to_port count_to_v4_addr raw_bytes_to_v4_addr @@ -2616,7 +2614,7 @@ function count_to_v4_addr%(ip: count%): addr ## ## b: The raw bytes (:bro:type:`string`) to convert. ## -## Returns: The byte :bro:type:`string` *ip* as :bro:type:`addr`. +## Returns: The byte :bro:type:`string` *b* as :bro:type:`addr`. ## ## .. bro:see:: raw_bytes_to_v4_addr to_addr to_subnet function raw_bytes_to_v4_addr%(b: string%): addr @@ -2635,7 +2633,7 @@ function raw_bytes_to_v4_addr%(b: string%): addr return new AddrVal(htonl(a)); %} -## Converts a :bro:type:`string` to an :bro:type:`port`. +## Converts a :bro:type:`string` to a :bro:type:`port`. ## ## s: The :bro:type:`string` to convert. ## @@ -2885,7 +2883,7 @@ function parse_ftp_port%(s: string%): ftp_port %} ## Converts a string representation of the FTP EPRT command to an ``ftp_port``. -## (see `RFC 2428 `_). +## See `RFC 2428 `_. ## The format is ``EPRT``, ## where ```` is a delimiter in the ASCII range 33-126 (usually ``|``). ## @@ -2976,7 +2974,7 @@ function fmt_ftp_port%(a: addr, p: port%): string ## Decode a NetBIOS name. See http://support.microsoft.com/kb/194203. ## -## name: The encoded NetBIOS name, e.g., ``"FEEIEFCAEOEFFEECEJEPFDCAEOEBENEF:``. +## name: The encoded NetBIOS name, e.g., ``"FEEIEFCAEOEFFEECEJEPFDCAEOEBENEF"``. ## ## Returns: The decoded NetBIOS name, e.g., ``"THE NETBIOS NAME"``. ## @@ -3009,7 +3007,7 @@ function decode_netbios_name%(name: string%): string return new StringVal(i, result); %} -## Converts a NetBIOS name type to its corresonding numeric value. +## Converts a NetBIOS name type to its corresponding numeric value. ## See http://support.microsoft.com/kb/163409. ## ## name: The NetBIOS name type. @@ -3029,7 +3027,7 @@ function decode_netbios_name_type%(name: string%): count ## ## bytestring: The string of bytes. ## -## Returns: The hexadecimal reprsentation of *bytestring*. +## Returns: The hexadecimal representation of *bytestring*. ## ## .. bro:see:: hexdump function bytestring_to_hexstr%(bytestring: string%): string @@ -3069,7 +3067,7 @@ function decode_base64%(s: string%): string ## s: The Base64-encoded string. ## ## a: The custom alphabet. The empty string indicates the default alphabet. The -## lengh of *a* must bt 64. For example, a custom alphabet could be +## length of *a* must be 64. For example, a custom alphabet could be ## ``"!#$%&/(),-.:;<>@[]^ `_{|}~abcdefghijklmnopqrstuvwxyz0123456789+?"``. ## ## Returns: The decoded version of *s*. @@ -3138,7 +3136,7 @@ function uuid_to_string%(uuid: string%): string ## ## p2: The second pattern. ## -## Returns: The compiled pattern of the concatentation of *p1* and *p2*. +## Returns: The compiled pattern of the concatenation of *p1* and *p2*. ## ## .. bro:see:: convert_for_pattern string_to_pattern ## @@ -3277,7 +3275,7 @@ function strftime%(fmt: string, d: time%) : string ## a: The address to mask. ## ## top_bits_to_keep: The number of top bits to keep in *a*; must be greater -## than 0 and less than 33. +## than 0 and less than 33 for IPv4, or 129 for IPv6. ## ## Returns: The address *a* masked down to *top_bits_to_keep* bits. ## @@ -3341,7 +3339,7 @@ function is_udp_port%(p: port%): bool ## ## p: The :bro:type:`port` to check. ## -## Returns: True iff *p* is a ICMP port. +## Returns: True iff *p* is an ICMP port. ## ## .. bro:see:: is_tcp_port is_udp_port function is_icmp_port%(p: port%): bool @@ -3383,7 +3381,7 @@ EnumVal* map_conn_type(TransportProto tp) ## ## cid: The connection identifier. ## -## Returns: The transport protocol of the connection identified by *id*. +## Returns: The transport protocol of the connection identified by *cid*. ## ## .. bro:see:: get_port_transport_proto ## get_orig_seq get_resp_seq @@ -3497,7 +3495,7 @@ const char* conn_id_string(Val* c) ## ## c: The HTTP connection. ## -## is_orig: If true, the client data is skipped and the server data otherwise. +## is_orig: If true, the client data is skipped, and the server data otherwise. ## ## .. bro:see:: skip_smtp_data function skip_http_entity_data%(c: connection, is_orig: bool%): any @@ -3572,7 +3570,7 @@ function dump_current_packet%(file_name: string%) : bool ## Returns the currently processed PCAP packet. ## -## Returns: The currently processed packet, which is as a record +## Returns: The currently processed packet, which is a record ## containing the timestamp, ``snaplen``, and packet data. ## ## .. bro:see:: dump_current_packet dump_packet send_current_packet @@ -3730,7 +3728,7 @@ function lookup_addr%(host: addr%) : string ## ## host: The hostname to lookup. ## -## Returns: A set of DNS A records associated with *host*. +## Returns: A set of DNS A and AAAA records associated with *host*. ## ## .. bro:see:: lookup_addr function lookup_hostname%(host: string%) : addr_set @@ -3897,6 +3895,7 @@ function lookup_location%(a: addr%) : geo_location %} ## Performs an AS lookup of an IP address. +## Requires Bro to be built with ``libgeoip``. ## ## a: The IP address to lookup. ## @@ -4096,7 +4095,7 @@ function x509_err2str%(err_num: count%): string ## Converts UNIX file permissions given by a mode to an ASCII string. ## -## mode: The permisssions, e.g., 644 or 755. +## mode: The permissions (an octal number like 0644 converted to decimal). ## ## Returns: A string representation of *mode* in the format ## ``rw[xsS]rw[xsS]rw[xtT]``. @@ -4273,7 +4272,7 @@ function analyzer_name%(aid: count%) : string ## ## cid: The connection ID. ## -## Returns: False if *id* does not point to an active connection and true +## Returns: False if *cid* does not point to an active connection, and true ## otherwise. ## ## .. note:: @@ -4295,10 +4294,10 @@ function skip_further_processing%(cid: conn_id%): bool ## ## cid: The connection identifier. ## -## do_record: True to enable packet contens and false to disable for the +## do_record: True to enable packet contents, and false to disable for the ## connection identified by *cid*. ## -## Returns: False if *id* does not point to an active connection and true +## Returns: False if *cid* does not point to an active connection, and true ## otherwise. ## ## .. bro:see:: skip_further_processing @@ -4309,7 +4308,7 @@ function skip_further_processing%(cid: conn_id%): bool ## connection, which is controlled separately by ## :bro:id:`skip_further_processing`. ## -## .. bro:see: get_contents_file set_contents_file +## .. bro:see:: get_contents_file set_contents_file function set_record_packets%(cid: conn_id, do_record: bool%): bool %{ Connection* c = sessions->FindConnection(cid); @@ -4326,7 +4325,7 @@ function set_record_packets%(cid: conn_id, do_record: bool%): bool ## cid: The connection ID. ## ## direction: Controls what sides of the connection to record. The argument can -## take one the four values: +## take one of the four values: ## ## - ``CONTENTS_NONE``: Stop recording the connection's content. ## - ``CONTENTS_ORIG``: Record the data sent by the connection @@ -4340,7 +4339,7 @@ function set_record_packets%(cid: conn_id, do_record: bool%): bool ## ## f: The file handle of the file to write the contents to. ## -## Returns: Returns false if *id* does not point to an active connection and +## Returns: Returns false if *cid* does not point to an active connection, and ## true otherwise. ## ## .. note:: @@ -4351,7 +4350,7 @@ function set_record_packets%(cid: conn_id, do_record: bool%): bool ## missing data; this can happen, e.g., due to an ## :bro:id:`ack_above_hole` event. ## -## .. bro:see: get_contents_file set_record_packets +## .. bro:see:: get_contents_file set_record_packets function set_contents_file%(cid: conn_id, direction: count, f: file%): bool %{ Connection* c = sessions->FindConnection(cid); @@ -4366,15 +4365,15 @@ function set_contents_file%(cid: conn_id, direction: count, f: file%): bool ## ## cid: The connection ID. ## -## direction: Controls what sides of the connection to record. SEe +## direction: Controls what sides of the connection to record. See ## :bro:id:`set_contents_file` for possible values. ## -## Returns: The :bro:type:`file` handle for the contentents file of the +## Returns: The :bro:type:`file` handle for the contents file of the ## connection identified by *cid*. If the connection exists -## but no contents file for *direction*, the function generates a -## error and returns a file handle to ``stderr``. +## but there is no contents file for *direction*, then the function +## generates an error and returns a file handle to ``stderr``. ## -## .. bro:see: set_contents_file set_record_packets +## .. bro:see:: set_contents_file set_record_packets function get_contents_file%(cid: conn_id, direction: count%): file %{ Connection* c = sessions->FindConnection(cid); @@ -4425,7 +4424,7 @@ function set_inactivity_timeout%(cid: conn_id, t: interval%): interval ## ## - ``LOGIN_STATE_AUTHENTICATE``: The connection is in its ## initial authentication dialog. -## - ``OGIN_STATE_LOGGED_IN``: The analyzer believes the user has +## - ``LOGIN_STATE_LOGGED_IN``: The analyzer believes the user has ## successfully authenticated. ## - ``LOGIN_STATE_SKIP``: The analyzer has skipped any further ## processing of the connection. @@ -4433,7 +4432,7 @@ function set_inactivity_timeout%(cid: conn_id, t: interval%): interval ## does not correctly know the state of the connection, and/or ## the username associated with it. ## -## .. bro:see: set_login_state +## .. bro:see:: set_login_state function get_login_state%(cid: conn_id%): count %{ Connection* c = sessions->FindConnection(cid); @@ -4456,9 +4455,9 @@ function get_login_state%(cid: conn_id%): count ## :bro:id:`get_login_state` for possible values. ## ## Returns: Returns false if *cid* is not an active connection -## or does not tagged as login analyzer, and true otherwise. +## or is not tagged as a login analyzer, and true otherwise. ## -## .. bro:see: get_login_state +## .. bro:see:: get_login_state function set_login_state%(cid: conn_id, new_state: count%): bool %{ Connection* c = sessions->FindConnection(cid); @@ -4590,9 +4589,9 @@ function disable_event_group%(group: string%) : any ## ## f: The path to the file. ## -## Returns: A :bro:type:`file` handle for subsequent operations. +## Returns: A :bro:type:`file` handle for subsequent operations. ## -## .. bro:see;: active_file open_for_append close write_file +## .. bro:see:: active_file open_for_append close write_file ## get_file_name set_buf flush_all mkdir enable_raw_output function open%(f: string%): file %{ @@ -4609,9 +4608,9 @@ function open%(f: string%): file ## ## f: The path to the file. ## -## Returns: A :bro:type:`file` handle for subsequent operations. +## Returns: A :bro:type:`file` handle for subsequent operations. ## -## .. bro:see;: active_file open close write_file +## .. bro:see:: active_file open close write_file ## get_file_name set_buf flush_all mkdir enable_raw_output function open_for_append%(f: string%): file %{ @@ -4619,13 +4618,12 @@ function open_for_append%(f: string%): file %} ## Closes an open file and flushes any buffered content. -## exists, this function appends to it (as opposed to :bro:id:`open`). ## ## f: A :bro:type:`file` handle to an open file. ## -## Returns: True on success. +## Returns: True on success. ## -## .. bro:see;: active_file open open_for_append write_file +## .. bro:see:: active_file open open_for_append write_file ## get_file_name set_buf flush_all mkdir enable_raw_output function close%(f: file%): bool %{ @@ -4638,9 +4636,9 @@ function close%(f: file%): bool ## ## data: The data to write to *f*. ## -## Returns: True on success. +## Returns: True on success. ## -## .. bro:see;: active_file open open_for_append close +## .. bro:see:: active_file open open_for_append close ## get_file_name set_buf flush_all mkdir enable_raw_output function write_file%(f: file, data: string%): bool %{ @@ -4656,11 +4654,11 @@ function write_file%(f: file, data: string%): bool ## f: A :bro:type:`file` handle to an open file. ## ## buffered: When true, *f* is fully buffered, i.e., bytes are saved in a -## buffered until the block size has been reached. When +## buffer until the block size has been reached. When ## false, *f* is line buffered, i.e., bytes are saved up until a ## newline occurs. ## -## .. bro:see;: active_file open open_for_append close +## .. bro:see:: active_file open open_for_append close ## get_file_name write_file flush_all mkdir enable_raw_output function set_buf%(f: file, buffered: bool%): any %{ @@ -4670,9 +4668,9 @@ function set_buf%(f: file, buffered: bool%): any ## Flushes all open files to disk. ## -## Returns: True on success. +## Returns: True on success. ## -## .. bro:see;: active_file open open_for_append close +## .. bro:see:: active_file open open_for_append close ## get_file_name write_file set_buf mkdir enable_raw_output function flush_all%(%): bool %{ @@ -4683,10 +4681,10 @@ function flush_all%(%): bool ## ## f: The directory name. ## -## Returns: Returns true if the operation succeeds and false if the +## Returns: Returns true if the operation succeeds, or false if the ## creation fails or if *f* exists already. ## -## .. bro:see;: active_file open_for_append close write_file +## .. bro:see:: active_file open_for_append close write_file ## get_file_name set_buf flush_all enable_raw_output function mkdir%(f: string%): bool %{ @@ -4731,7 +4729,7 @@ function get_file_name%(f: file%): string ## ## f: An open file handle. ## -## Returns: Rotations statistics which include the original file name, the name +## Returns: Rotation statistics which include the original file name, the name ## after the rotation, and the time when *f* was opened/closed. ## ## .. bro:see:: rotate_file_by_name calc_next_rotate @@ -4755,7 +4753,7 @@ function rotate_file%(f: file%): rotate_info ## ## f: The name of the file to rotate ## -## Returns: Rotations statistics which include the original file name, the name +## Returns: Rotation statistics which include the original file name, the name ## after the rotation, and the time when *f* was opened/closed. ## ## .. bro:see:: rotate_file calc_next_rotate @@ -4851,7 +4849,7 @@ function disable_print_hook%(f: file%): any return 0; %} -## Prevents escaping of non-ASCII character when writing to a file. +## Prevents escaping of non-ASCII characters when writing to a file. ## This function is equivalent to :bro:attr:`&disable_print_hook`. ## ## f: The file to disable raw output for. @@ -5213,9 +5211,9 @@ function checkpoint_state%(%) : bool return new Val(persistence_serializer->WriteState(true), TYPE_BOOL); %} -## Reads persistent state from the \texttt{.state} directory and populates the -## in-memory data structures accordingly. This function is the dual to -## :bro:id:`checkpoint_state`. +## Reads persistent state and populates the in-memory data structures +## accordingly. Persistent state is read from the ``.state`` directory. +## This function is the dual to :bro:id:`checkpoint_state`. ## ## Returns: True on success. ## @@ -5267,16 +5265,16 @@ function capture_state_updates%(filename: string%) : bool ## ## ip: The IP address of the remote peer. ## -## port: The port of the remote peer. +## p: The port of the remote peer. ## -## our_class: If an non-empty string, the remote (listening) peer checks it +## our_class: If a non-empty string, then the remote (listening) peer checks it ## against its class name in its peer table and terminates the ## connection if they don't match. ## ## retry: If the connection fails, try to reconnect with the peer after this ## time interval. ## -## ssl: If true, uses SSL to encrypt the session. +## ssl: If true, use SSL to encrypt the session. ## ## Returns: A locally unique ID of the new peer. ## @@ -5299,7 +5297,7 @@ function connect%(ip: addr, p: port, our_class: string, retry: interval, ssl: bo ## Terminate the connection with a peer. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## Returns: True on success. ## @@ -5313,7 +5311,7 @@ function disconnect%(p: event_peer%) : bool ## Subscribes to all events from a remote peer whose names match a given ## pattern. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## handlers: The pattern describing the events to request from peer *p*. ## @@ -5331,7 +5329,7 @@ function request_remote_events%(p: event_peer, handlers: pattern%) : bool ## Requests synchronization of IDs with a remote peer. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## auth: If true, the local instance considers its current state authoritative ## and sends it to *p* right after the handshake. @@ -5349,7 +5347,7 @@ function request_remote_sync%(p: event_peer, auth: bool%) : bool ## Requests logs from a remote peer. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## Returns: True on success. ## @@ -5361,9 +5359,11 @@ function request_remote_logs%(p: event_peer%) : bool return new Val(remote_serializer->RequestLogs(id), TYPE_BOOL); %} -## Sets a boolean flag whether Bro accepts state from a remote peer. +## Sets a boolean flag indicating whether Bro accepts state from a remote peer. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. +## +## accept: True if Bro accepts state from peer *p*, or false otherwise. ## ## Returns: True on success. ## @@ -5379,7 +5379,7 @@ function set_accept_state%(p: event_peer, accept: bool%) : bool ## Sets the compression level of the session with a remote peer. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## level: Allowed values are in the range *[0, 9]*, where 0 is the default and ## means no compression. @@ -5394,11 +5394,11 @@ function set_compression_level%(p: event_peer, level: count%) : bool TYPE_BOOL); %} -## Listens on address a given IP address and port for remote connections. +## Listens on a given IP address and port for remote connections. ## ## ip: The IP address to bind to. ## -## p: The TCP port to listen to. +## p: The TCP port to listen on. ## ## ssl: If true, Bro uses SSL to encrypt the session. ## @@ -5420,7 +5420,7 @@ function is_remote_event%(%) : bool ## Sends all persistent state to a remote peer. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## Returns: True on success. ## @@ -5431,10 +5431,10 @@ function send_state%(p: event_peer%) : bool return new Val(persistence_serializer->SendState(id, true), TYPE_BOOL); %} -## Sends a global identifier to a remote peer, which them might install it +## Sends a global identifier to a remote peer, which then might install it ## locally. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## id: The identifier to send. ## @@ -5468,7 +5468,7 @@ function terminate_communication%(%) : bool ## Signals a remote peer that the local Bro instance finished the initial ## handshake. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## Returns: True on success. function complete_handshake%(p: event_peer%) : bool @@ -5481,7 +5481,7 @@ function complete_handshake%(p: event_peer%) : bool ## for :bro:id:`remote_pong`, this function can be used to measure latency ## between two peers. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## seq: A sequence number (also included by :bro:id:`remote_pong`). ## @@ -5496,7 +5496,7 @@ function send_ping%(p: event_peer, seq: count%) : bool ## Sends the currently processed packet to a remote peer. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## Returns: True if sending the packet succeeds. ## @@ -5522,7 +5522,7 @@ function send_current_packet%(p: event_peer%) : bool ## Returns the peer who generated the last event. ## -## Returns: The ID of the peer who genereated the last event. +## Returns: The ID of the peer who generated the last event. ## ## .. bro:see:: get_local_event_peer function get_event_peer%(%) : event_peer @@ -5565,7 +5565,7 @@ function get_local_event_peer%(%) : event_peer ## Sends a capture filter to a remote peer. ## -## p: The peer ID return from :bro:id:`connect`. +## p: The peer ID returned from :bro:id:`connect`. ## ## s: The capture filter. ## @@ -5582,7 +5582,7 @@ function send_capture_filter%(p: event_peer, s: string%) : bool ## distributed trace processing with communication enabled ## (*pseudo-realtime* mode). ## -## .. bro:see: continue_processing suspend_state_updates resume_state_updates +## .. bro:see:: continue_processing suspend_state_updates resume_state_updates function suspend_processing%(%) : any %{ net_suspend_processing(); @@ -5591,7 +5591,7 @@ function suspend_processing%(%) : any ## Resumes Bro's packet processing. ## -## .. bro:see: suspend_processing suspend_state_updates resume_state_updates +## .. bro:see:: suspend_processing suspend_state_updates resume_state_updates function continue_processing%(%) : any %{ net_continue_processing(); @@ -5600,7 +5600,7 @@ function continue_processing%(%) : any ## Stops propagating :bro:attr:`&synchronized` accesses. ## -## .. bro:see: suspend_processing continue_processing resume_state_updates +## .. bro:see:: suspend_processing continue_processing resume_state_updates function suspend_state_updates%(%) : any %{ if ( remote_serializer ) @@ -5610,7 +5610,7 @@ function suspend_state_updates%(%) : any ## Resumes propagating :bro:attr:`&synchronized` accesses. ## -## .. bro:see: suspend_processing continue_processing suspend_state_updates +## .. bro:see:: suspend_processing continue_processing suspend_state_updates function resume_state_updates%(%) : any %{ if ( remote_serializer ) diff --git a/src/strings.bif b/src/strings.bif index ebe16529ea..27c11b4013 100644 --- a/src/strings.bif +++ b/src/strings.bif @@ -11,8 +11,8 @@ using namespace std; %%} -## Concates all arguments into a single string. The function takes a variable -## number of arguments of type string and stiches them together. +## Concatenates all arguments into a single string. The function takes a +## variable number of arguments of type string and stitches them together. ## ## Returns: The concatenation of all (string) arguments. ## @@ -157,9 +157,9 @@ function join_string_array%(sep: string, a: string_array%): string ## ## sep: The separator to place between each element. ## -## a: The :bro:type:`string_vec` (``vector of string``). +## vec: The :bro:type:`string_vec` (``vector of string``). ## -## Returns: The concatenation of all elements in *a*, with *sep* placed +## Returns: The concatenation of all elements in *vec*, with *sep* placed ## between each element. ## ## .. bro:see:: cat cat_sep string_cat cat_string_array cat_string_array_n @@ -219,7 +219,7 @@ function sort_string_array%(a: string_array%): string_array ## Returns an edited version of a string that applies a special ## "backspace character" (usually ``\x08`` for backspace or ``\x7f`` for DEL). -## For ## example, ``edit("hello there", "e")`` returns ``"llo t"``. +## For example, ``edit("hello there", "e")`` returns ``"llo t"``. ## ## arg_s: The string to edit. ## @@ -229,7 +229,7 @@ function sort_string_array%(a: string_array%): string_array ## the string. ## ## Returns: An edited version of *arg_s* where *arg_edit_char* triggers the -## deletetion of the last character. +## deletion of the last character. ## ## .. bro:see:: clean ## to_string_literal @@ -278,7 +278,7 @@ function byte_len%(s: string%): count return new Val(s->Len(), TYPE_COUNT); %} -## Get a substring of from a string, given a starting position length. +## Get a substring from a string, given a starting position and length. ## ## s: The string to obtain a substring from. ## @@ -486,10 +486,10 @@ function split%(str: string, re: pattern%): string_array return do_split(str, re, 0, 0, 0); %} -## Splits a string *once* into a a two-element array of strings according to a -## pattern. This function is the same as :bro:id:`split`, but * is only split -## once (if possible) at the earliest position and an array of two strings is -## returned. +## Splits a string *once* into a two-element array of strings according to a +## pattern. This function is the same as :bro:id:`split`, but *str* is only +## split once (if possible) at the earliest position and an array of two strings +## is returned. ## ## str: The string to split. ## @@ -518,7 +518,7 @@ function split1%(str: string, re: pattern%): string_array ## ## Returns: An array of strings where each two successive elements correspond ## to a substring in *str* of the part not matching *re* (odd-indexed) -## and thei part that matches *re* (even-indexed). +## and the part that matches *re* (even-indexed). ## ## .. bro:see:: split split1 split_n str_split function split_all%(str: string, re: pattern%): string_array @@ -568,7 +568,7 @@ function split_complete%(str: string, ## ## re: The pattern being replaced with *repl*. ## -## repl: The string that replacs *re*. +## repl: The string that replaces *re*. ## ## Returns: A copy of *str* with the first occurence of *re* replaced with ## *repl*. @@ -579,16 +579,16 @@ function sub%(str: string, re: pattern, repl: string%): string return do_sub(str, re, repl, 0); %} -## Substitutes a given replacement string for the all occurrences of a pattern +## Substitutes a given replacement string for all occurrences of a pattern ## in a given string. ## ## str: The string to perform the substitution in. ## ## re: The pattern being replaced with *repl*. ## -## repl: The string that replacs *re*. +## repl: The string that replaces *re*. ## -## Returns: A copy of *str* with all occurences of *re* replaced with *repl*. +## Returns: A copy of *str* with all occurrences of *re* replaced with *repl*. ## ## .. bro:see:: sub subst_string function gsub%(str: string, re: pattern, repl: string%): string @@ -597,7 +597,7 @@ function gsub%(str: string, re: pattern, repl: string%): string %} -## Lexicographically compares two string. +## Lexicographically compares two strings. ## ## s1: The first string. ## @@ -616,7 +616,7 @@ function strcmp%(s1: string, s2: string%): int ## ## little: The (smaller) string to find inside *big*. ## -## Returns: The location of *little* in *big* or 0 if *little* is not found in +## Returns: The location of *little* in *big*, or 0 if *little* is not found in ## *big*. ## ## .. bro:see:: find_all find_last @@ -685,7 +685,7 @@ function subst_string%(s: string, from: string, to: string%): string ## str: The string to convert to lowercase letters. ## ## Returns: A copy of the given string with the uppercase letters (as indicated -## by ``isascii`` and \verb|isupper|``) folded to lowercase +## by ``isascii`` and ``isupper``) folded to lowercase ## (via ``tolower``). ## ## .. bro:see:: to_upper is_ascii @@ -714,7 +714,7 @@ function to_lower%(str: string%): string ## str: The string to convert to uppercase letters. ## ## Returns: A copy of the given string with the lowercase letters (as indicated -## by ``isascii`` and \verb|islower|``) folded to uppercase +## by ``isascii`` and ``islower``) folded to uppercase ## (via ``toupper``). ## ## .. bro:see:: to_lower is_ascii @@ -744,7 +744,7 @@ function to_upper%(str: string%): string ## - ``NUL`` to ``\0`` ## - ``DEL`` to ``^?`` ## - values <= 26 to ``^[A-Z]`` -## - values not in *[32, 126]** to ``%XX`` +## - values not in *[32, 126]* to ``%XX`` ## ## If the string does not yet have a trailing NUL, one is added. ## @@ -765,7 +765,7 @@ function clean%(str: string%): string ## - ``NUL`` to ``\0`` ## - ``DEL`` to ``^?`` ## - values <= 26 to ``^[A-Z]`` -## - values not in *[32, 126]** to ``%XX`` +## - values not in *[32, 126]* to ``%XX`` ## ## str: The string to escape. ## @@ -831,14 +831,16 @@ function string_to_ascii_hex%(s: string%): string return new StringVal(new BroString(1, (u_char*) x, s->Len() * 2)); %} -## Uses the Smith Waterman algorithm to find similar/overlapping substrings. +## Uses the Smith-Waterman algorithm to find similar/overlapping substrings. ## See `Wikipedia `_. ## ## s1: The first string. ## ## s2: The second string. ## -## Returns: The result of the Smit Waterman algorithm calculation. +## params: Parameters for the Smith-Waterman algorithm. +## +## Returns: The result of the Smith-Waterman algorithm calculation. function str_smith_waterman%(s1: string, s2: string, params: sw_params%) : sw_substring_vec %{ SWParams sw_params(params->AsRecordVal()->Lookup(0)->AsCount(), From 5ab765b4b6643fa872889ef03f56604ba7748a2a Mon Sep 17 00:00:00 2001 From: Daniel Thayer Date: Fri, 18 May 2012 11:23:09 -0500 Subject: [PATCH 07/15] Replace ip6_hdr_chain with ip6_ext_hdr in comments This fixes some warnings that were appearing when building the documentation. --- scripts/base/init-bare.bro | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 20ce7b8ff5..73f7d725d4 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -967,7 +967,7 @@ const IPPROTO_MOBILITY = 135; ##< IPv6 mobility header. ## Values extracted from an IPv6 extension header's (e.g. hop-by-hop or ## destination option headers) option field. ## -## .. bro:see:: ip6_hdr ip6_hdr_chain ip6_hopopts ip6_dstopts +## .. bro:see:: ip6_hdr ip6_ext_hdr ip6_hopopts ip6_dstopts type ip6_option: record { otype: count; ##< Option type. len: count; ##< Option data length. @@ -976,7 +976,7 @@ type ip6_option: record { ## Values extracted from an IPv6 Hop-by-Hop options extension header. ## -## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain ip6_option +## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_ext_hdr ip6_option type ip6_hopopts: record { ## Protocol number of the next header (RFC 1700 et seq., IANA assigned ## number), e.g. :bro:id:`IPPROTO_ICMP`. @@ -989,7 +989,7 @@ type ip6_hopopts: record { ## Values extracted from an IPv6 Destination options extension header. ## -## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain ip6_option +## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_ext_hdr ip6_option type ip6_dstopts: record { ## Protocol number of the next header (RFC 1700 et seq., IANA assigned ## number), e.g. :bro:id:`IPPROTO_ICMP`. @@ -1002,7 +1002,7 @@ type ip6_dstopts: record { ## Values extracted from an IPv6 Routing extension header. ## -## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain +## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_ext_hdr type ip6_routing: record { ## Protocol number of the next header (RFC 1700 et seq., IANA assigned ## number), e.g. :bro:id:`IPPROTO_ICMP`. @@ -1019,7 +1019,7 @@ type ip6_routing: record { ## Values extracted from an IPv6 Fragment extension header. ## -## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain +## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_ext_hdr type ip6_fragment: record { ## Protocol number of the next header (RFC 1700 et seq., IANA assigned ## number), e.g. :bro:id:`IPPROTO_ICMP`. @@ -1038,7 +1038,7 @@ type ip6_fragment: record { ## Values extracted from an IPv6 Authentication extension header. ## -## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain +## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_ext_hdr type ip6_ah: record { ## Protocol number of the next header (RFC 1700 et seq., IANA assigned ## number), e.g. :bro:id:`IPPROTO_ICMP`. @@ -1057,7 +1057,7 @@ type ip6_ah: record { ## Values extracted from an IPv6 ESP extension header. ## -## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain +## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_ext_hdr type ip6_esp: record { ## Security Parameters Index. spi: count; @@ -1067,7 +1067,7 @@ type ip6_esp: record { ## Values extracted from an IPv6 Mobility Binding Refresh Request message. ## -## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg +## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_ext_hdr ip6_mobility_msg type ip6_mobility_brr: record { ## Reserved. rsv: count; @@ -1077,7 +1077,7 @@ type ip6_mobility_brr: record { ## Values extracted from an IPv6 Mobility Home Test Init message. ## -## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg +## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_ext_hdr ip6_mobility_msg type ip6_mobility_hoti: record { ## Reserved. rsv: count; @@ -1089,7 +1089,7 @@ type ip6_mobility_hoti: record { ## Values extracted from an IPv6 Mobility Care-of Test Init message. ## -## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg +## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_ext_hdr ip6_mobility_msg type ip6_mobility_coti: record { ## Reserved. rsv: count; @@ -1101,7 +1101,7 @@ type ip6_mobility_coti: record { ## Values extracted from an IPv6 Mobility Home Test message. ## -## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg +## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_ext_hdr ip6_mobility_msg type ip6_mobility_hot: record { ## Home Nonce Index. nonce_idx: count; @@ -1115,7 +1115,7 @@ type ip6_mobility_hot: record { ## Values extracted from an IPv6 Mobility Care-of Test message. ## -## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg +## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_ext_hdr ip6_mobility_msg type ip6_mobility_cot: record { ## Care-of Nonce Index. nonce_idx: count; @@ -1129,7 +1129,7 @@ type ip6_mobility_cot: record { ## Values extracted from an IPv6 Mobility Binding Update message. ## -## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg +## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_ext_hdr ip6_mobility_msg type ip6_mobility_bu: record { ## Sequence number. seq: count; @@ -1149,7 +1149,7 @@ type ip6_mobility_bu: record { ## Values extracted from an IPv6 Mobility Binding Acknowledgement message. ## -## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg +## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_ext_hdr ip6_mobility_msg type ip6_mobility_back: record { ## Status. status: count; @@ -1165,7 +1165,7 @@ type ip6_mobility_back: record { ## Values extracted from an IPv6 Mobility Binding Error message. ## -## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain ip6_mobility_msg +## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_ext_hdr ip6_mobility_msg type ip6_mobility_be: record { ## Status. status: count; @@ -1177,7 +1177,7 @@ type ip6_mobility_be: record { ## Values extracted from an IPv6 Mobility header's message data. ## -## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_hdr_chain +## .. bro:see:: ip6_mobility_hdr ip6_hdr ip6_ext_hdr type ip6_mobility_msg: record { ## The type of message from the header's MH Type field. id: count; @@ -1201,7 +1201,7 @@ type ip6_mobility_msg: record { ## Values extracted from an IPv6 Mobility header. ## -## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_hdr_chain +## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr ip6_ext_hdr type ip6_mobility_hdr: record { ## Protocol number of the next header (RFC 1700 et seq., IANA assigned ## number), e.g. :bro:id:`IPPROTO_ICMP`. @@ -1244,7 +1244,7 @@ type ip6_ext_hdr: record { ## Values extracted from an IPv6 header. ## -## .. bro:see:: pkt_hdr ip4_hdr ip6_hdr_chain ip6_hopopts ip6_dstopts +## .. bro:see:: pkt_hdr ip4_hdr ip6_ext_hdr ip6_hopopts ip6_dstopts ## ip6_routing ip6_fragment ip6_ah ip6_esp type ip6_hdr: record { class: count; ##< Traffic class. From 5312b21d7bd4e19f7fbd8dffa6e0f6277014fb01 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Tue, 22 May 2012 15:18:33 -0500 Subject: [PATCH 08/15] Improve availability of IPv6 flow label in connection records. Without this change, flow labeling of connections over IPv6 are only available in the per-packet types of events (e.g. new_packet) in which header fields can be inspected, but now minimal tracking of the most recent flow label is done internally and that's available per-connection for all events that use connection record arguments. Specifically, this adds a "flow_label" field to the "endpoint" record type, which is used for both the "orig" and "resp" fields of "connection" records. The new "connection_flow_label_changed" event also allows tracking of changes in flow labels: it's raised each time one direction of the connection starts using a different label. --- scripts/base/init-bare.bro | 7 +- src/Conn.cc | 49 +++++++++++- src/Conn.h | 7 +- src/IP.h | 6 ++ src/Sessions.cc | 10 ++- src/Sessions.h | 2 +- src/event.bif | 14 ++++ .../Baseline/core.ipv6-flow-labels/output | 74 +++++++++++++++++++ testing/btest/core/ipv6-flow-labels.test | 32 ++++++++ 9 files changed, 192 insertions(+), 9 deletions(-) create mode 100644 testing/btest/Baseline/core.ipv6-flow-labels/output create mode 100644 testing/btest/core/ipv6-flow-labels.test diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 20ce7b8ff5..dadeab734a 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -178,9 +178,9 @@ type endpoint_stats: record { ## use ``count``. That should be changed. type AnalyzerID: count; -## Statistics about an endpoint. +## Statistics about a :bro:type:`connection` endpoint. ## -## todo::Where is this used? +## .. bro:see:: connection type endpoint: record { size: count; ##< Logical size of data sent (for TCP: derived from sequence numbers). ## Endpoint state. For TCP connection, one of the constants: @@ -194,6 +194,9 @@ type endpoint: record { ## Number of IP-level bytes sent. Only set if :bro:id:`use_conn_size_analyzer` is ## true. num_bytes_ip: count &optional; + ## The current IPv6 flow label that the connection endpoint is using. + ## Always 0 if the connection is over IPv4. + flow_label: count; }; # A connection. This is Bro's basic connection type describing IP- and diff --git a/src/Conn.cc b/src/Conn.cc index acf17fab3a..3835097b6a 100644 --- a/src/Conn.cc +++ b/src/Conn.cc @@ -111,7 +111,8 @@ unsigned int Connection::external_connections = 0; IMPLEMENT_SERIAL(Connection, SER_CONNECTION); -Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id) +Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id, + uint32 flow) { sessions = s; key = k; @@ -122,6 +123,10 @@ Connection::Connection(NetSessions* s, HashKey* k, double t, const ConnID* id) orig_port = id->src_port; resp_port = id->dst_port; proto = TRANSPORT_UNKNOWN; + orig_flow_label = flow; + resp_flow_label = 0; + saw_first_orig_packet = 1; + saw_first_resp_packet = 0; conn_val = 0; login_conn = 0; @@ -323,10 +328,12 @@ RecordVal* Connection::BuildConnVal() RecordVal *orig_endp = new RecordVal(endpoint); orig_endp->Assign(0, new Val(0, TYPE_COUNT)); orig_endp->Assign(1, new Val(0, TYPE_COUNT)); + orig_endp->Assign(4, new Val(orig_flow_label, TYPE_COUNT)); RecordVal *resp_endp = new RecordVal(endpoint); resp_endp->Assign(0, new Val(0, TYPE_COUNT)); resp_endp->Assign(1, new Val(0, TYPE_COUNT)); + resp_endp->Assign(4, new Val(resp_flow_label, TYPE_COUNT)); conn_val->Assign(0, id_val); conn_val->Assign(1, orig_endp); @@ -675,6 +682,14 @@ void Connection::FlipRoles() resp_port = orig_port; orig_port = tmp_port; + bool tmp_bool = saw_first_resp_packet; + saw_first_resp_packet = saw_first_orig_packet; + saw_first_orig_packet = tmp_bool; + + uint32 tmp_flow = resp_flow_label; + resp_flow_label = orig_flow_label; + orig_flow_label = tmp_flow; + Unref(conn_val); conn_val = 0; @@ -882,3 +897,35 @@ void Connection::SetRootAnalyzer(TransportLayerAnalyzer* analyzer, PIA* pia) root_analyzer = analyzer; primary_PIA = pia; } + +void Connection::CheckFlowLabel(bool is_orig, uint32 flow_label) + { + uint32& my_flow_label = is_orig ? orig_flow_label : resp_flow_label; + + if ( my_flow_label != flow_label ) + { + if ( conn_val ) + { + RecordVal *endp = conn_val->Lookup(is_orig ? 1 : 2)->AsRecordVal(); + endp->Assign(4, new Val(flow_label, TYPE_COUNT)); + } + + if ( connection_flow_label_changed && + (is_orig ? saw_first_orig_packet : saw_first_resp_packet) ) + { + val_list* vl = new val_list(4); + vl->append(BuildConnVal()); + vl->append(new Val(is_orig, TYPE_BOOL)); + vl->append(new Val(my_flow_label, TYPE_COUNT)); + vl->append(new Val(flow_label, TYPE_COUNT)); + ConnectionEvent(connection_flow_label_changed, 0, vl); + } + + my_flow_label = flow_label; + } + + if ( is_orig ) + saw_first_orig_packet = 1; + else + saw_first_resp_packet = 1; + } diff --git a/src/Conn.h b/src/Conn.h index b3eb9013d0..7404721968 100644 --- a/src/Conn.h +++ b/src/Conn.h @@ -50,7 +50,8 @@ class Analyzer; class Connection : public BroObj { public: - Connection(NetSessions* s, HashKey* k, double t, const ConnID* id); + Connection(NetSessions* s, HashKey* k, double t, const ConnID* id, + uint32 flow); virtual ~Connection(); // Invoked when connection is about to be removed. Use Ref(this) @@ -241,6 +242,8 @@ public: void SetUID(uint64 arg_uid) { uid = arg_uid; } + void CheckFlowLabel(bool is_orig, uint32 flow_label); + protected: Connection() { persistent = 0; } @@ -271,6 +274,7 @@ protected: IPAddr resp_addr; uint32 orig_port, resp_port; // in network order TransportProto proto; + uint32 orig_flow_label, resp_flow_label; // most recent IPv6 flow labels double start_time, last_time; double inactivity_timeout; RecordVal* conn_val; @@ -286,6 +290,7 @@ protected: unsigned int record_packets:1, record_contents:1; unsigned int persistent:1; unsigned int record_current_packet:1, record_current_content:1; + unsigned int saw_first_orig_packet:1, saw_first_resp_packet:1; // Count number of connections. static unsigned int total_connections; diff --git a/src/IP.h b/src/IP.h index 502ae857c0..c3a74b4a01 100644 --- a/src/IP.h +++ b/src/IP.h @@ -524,6 +524,12 @@ public: int DF() const { return ip4 ? ((ntohs(ip4->ip_off) & 0x4000) != 0) : 0; } + /** + * Returns value of an IPv6 header's flow label field or 0 if it's IPv4. + */ + uint32 FlowLabel() const + { return ip4 ? 0 : (ntohl(ip6->ip6_flow) & 0x000fffff); } + /** * Returns number of IP headers in packet (includes IPv6 extension headers). */ diff --git a/src/Sessions.cc b/src/Sessions.cc index 7da1f088de..4419936fbd 100644 --- a/src/Sessions.cc +++ b/src/Sessions.cc @@ -602,7 +602,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, conn = (Connection*) d->Lookup(h); if ( ! conn ) { - conn = NewConn(h, t, &id, data, proto); + conn = NewConn(h, t, &id, data, proto, ip_hdr->FlowLabel()); if ( conn ) d->Insert(h, conn); } @@ -623,7 +623,7 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, conn->Event(connection_reused, 0); Remove(conn); - conn = NewConn(h, t, &id, data, proto); + conn = NewConn(h, t, &id, data, proto, ip_hdr->FlowLabel()); if ( conn ) d->Insert(h, conn); } @@ -644,6 +644,8 @@ void NetSessions::DoNextPacket(double t, const struct pcap_pkthdr* hdr, int is_orig = (id.src_addr == conn->OrigAddr()) && (id.src_port == conn->OrigPort()); + conn->CheckFlowLabel(is_orig, ip_hdr->FlowLabel()); + Val* pkt_hdr_val = 0; if ( ipv6_ext_headers && ip_hdr->NumHeaders() > 1 ) @@ -1002,7 +1004,7 @@ void NetSessions::GetStats(SessionStats& s) const } Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id, - const u_char* data, int proto) + const u_char* data, int proto, uint32 flow_label) { // FIXME: This should be cleaned up a bit, it's too protocol-specific. // But I'm not yet sure what the right abstraction for these things is. @@ -1058,7 +1060,7 @@ Connection* NetSessions::NewConn(HashKey* k, double t, const ConnID* id, id = &flip_id; } - Connection* conn = new Connection(this, k, t, id); + Connection* conn = new Connection(this, k, t, id, flow_label); conn->SetTransport(tproto); dpm->BuildInitialAnalyzerTree(tproto, conn, data); diff --git a/src/Sessions.h b/src/Sessions.h index 06c6057dbf..d29ab0eeab 100644 --- a/src/Sessions.h +++ b/src/Sessions.h @@ -142,7 +142,7 @@ protected: friend class TimerMgrExpireTimer; Connection* NewConn(HashKey* k, double t, const ConnID* id, - const u_char* data, int proto); + const u_char* data, int proto, uint32 flow_label); // Check whether the tag of the current packet is consistent with // the given connection. Returns: diff --git a/src/event.bif b/src/event.bif index ded054dd53..80bb46e561 100644 --- a/src/event.bif +++ b/src/event.bif @@ -401,6 +401,20 @@ event connection_reused%(c: connection%); ## new_connection new_connection_contents partial_connection event connection_status_update%(c: connection%); +## Generated for a connection over IPv6 when one direction has changed +## the flow label that it's using. +## +## c: The connection. +## +## is_orig: True if the event is raised for the originator side. +## +## old_label: The old flow label that the endpoint was using. +## +## new_label: The new flow label that the endpoint is using. +## +## .. bro:see:: connection_established new_connection +event connection_flow_label_changed%(c: connection, is_orig: bool, old_label: count, new_label: count%); + ## Generated at the end of reassembled TCP connections. The TCP reassembler ## raised the event once for each endpoint of a connection when it finished ## reassembling the corresponding side of the communication. diff --git a/testing/btest/Baseline/core.ipv6-flow-labels/output b/testing/btest/Baseline/core.ipv6-flow-labels/output new file mode 100644 index 0000000000..9f7292d485 --- /dev/null +++ b/testing/btest/Baseline/core.ipv6-flow-labels/output @@ -0,0 +1,74 @@ +new_connection: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49185/tcp, resp_h=2001:470:4867:99::21, resp_p=21/tcp] + orig_flow 0 + resp_flow 0 +connection_established: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49185/tcp, resp_h=2001:470:4867:99::21, resp_p=21/tcp] + orig_flow 0 + resp_flow 0 +connection_flow_label_changed(resp): [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49185/tcp, resp_h=2001:470:4867:99::21, resp_p=21/tcp] + orig_flow 0 + resp_flow 7407 + old_label 0 + new_label 7407 +new_connection: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49186/tcp, resp_h=2001:470:4867:99::21, resp_p=57086/tcp] + orig_flow 0 + resp_flow 0 +connection_established: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49186/tcp, resp_h=2001:470:4867:99::21, resp_p=57086/tcp] + orig_flow 0 + resp_flow 0 +connection_flow_label_changed(resp): [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49186/tcp, resp_h=2001:470:4867:99::21, resp_p=57086/tcp] + orig_flow 0 + resp_flow 176012 + old_label 0 + new_label 176012 +new_connection: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49187/tcp, resp_h=2001:470:4867:99::21, resp_p=57087/tcp] + orig_flow 0 + resp_flow 0 +connection_established: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49187/tcp, resp_h=2001:470:4867:99::21, resp_p=57087/tcp] + orig_flow 0 + resp_flow 0 +connection_flow_label_changed(resp): [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49187/tcp, resp_h=2001:470:4867:99::21, resp_p=57087/tcp] + orig_flow 0 + resp_flow 390927 + old_label 0 + new_label 390927 +new_connection: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49188/tcp, resp_h=2001:470:4867:99::21, resp_p=57088/tcp] + orig_flow 0 + resp_flow 0 +connection_established: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49188/tcp, resp_h=2001:470:4867:99::21, resp_p=57088/tcp] + orig_flow 0 + resp_flow 0 +connection_flow_label_changed(resp): [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49188/tcp, resp_h=2001:470:4867:99::21, resp_p=57088/tcp] + orig_flow 0 + resp_flow 364705 + old_label 0 + new_label 364705 +connection_state_remove: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49186/tcp, resp_h=2001:470:4867:99::21, resp_p=57086/tcp] + orig_flow 0 + resp_flow 176012 +connection_state_remove: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49187/tcp, resp_h=2001:470:4867:99::21, resp_p=57087/tcp] + orig_flow 0 + resp_flow 390927 +connection_state_remove: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49188/tcp, resp_h=2001:470:4867:99::21, resp_p=57088/tcp] + orig_flow 0 + resp_flow 364705 +new_connection: [orig_h=2001:470:4867:99::21, orig_p=55785/tcp, resp_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, resp_p=49189/tcp] + orig_flow 267377 + resp_flow 0 +connection_established: [orig_h=2001:470:4867:99::21, orig_p=55785/tcp, resp_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, resp_p=49189/tcp] + orig_flow 267377 + resp_flow 126027 +new_connection: [orig_h=2001:470:4867:99::21, orig_p=55647/tcp, resp_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, resp_p=49190/tcp] + orig_flow 355265 + resp_flow 0 +connection_established: [orig_h=2001:470:4867:99::21, orig_p=55647/tcp, resp_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, resp_p=49190/tcp] + orig_flow 355265 + resp_flow 126028 +connection_state_remove: [orig_h=2001:470:4867:99::21, orig_p=55785/tcp, resp_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, resp_p=49189/tcp] + orig_flow 267377 + resp_flow 126027 +connection_state_remove: [orig_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, orig_p=49185/tcp, resp_h=2001:470:4867:99::21, resp_p=21/tcp] + orig_flow 0 + resp_flow 7407 +connection_state_remove: [orig_h=2001:470:4867:99::21, orig_p=55647/tcp, resp_h=2001:470:1f11:81f:c999:d94:aa7c:2e3e, resp_p=49190/tcp] + orig_flow 355265 + resp_flow 126028 diff --git a/testing/btest/core/ipv6-flow-labels.test b/testing/btest/core/ipv6-flow-labels.test new file mode 100644 index 0000000000..b4e60cb0a4 --- /dev/null +++ b/testing/btest/core/ipv6-flow-labels.test @@ -0,0 +1,32 @@ +# @TEST-EXEC: bro -b -r $TRACES/ipv6-ftp.trace %INPUT >output +# @TEST-EXEC: btest-diff output + +function print_connection(c: connection, event_name: string) + { + print fmt("%s: %s", event_name, c$id); + print fmt(" orig_flow %d", c$orig$flow_label); + print fmt(" resp_flow %d", c$resp$flow_label); + } + +event new_connection(c: connection) + { + print_connection(c, "new_connection"); + } + +event connection_established(c: connection) + { + print_connection(c, "connection_established"); + } + +event connection_state_remove(c: connection) + { + print_connection(c, "connection_state_remove"); + } + +event connection_flow_label_changed(c: connection, is_orig: bool, + old_label: count, new_label: count) + { + print_connection(c, fmt("connection_flow_label_changed(%s)", is_orig ? "orig" : "resp")); + print fmt(" old_label %d", old_label); + print fmt(" new_label %d", new_label); + } From 074a0a9dce5dca4219e213c83264e16ef4450733 Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Wed, 23 May 2012 14:29:16 -0500 Subject: [PATCH 09/15] Documentation fixes. --- scripts/base/init-bare.bro | 2 +- scripts/base/protocols/conn/main.bro | 2 +- src/event.bif | 9 +++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/scripts/base/init-bare.bro b/scripts/base/init-bare.bro index 73f7d725d4..17748917b7 100644 --- a/scripts/base/init-bare.bro +++ b/scripts/base/init-bare.bro @@ -219,7 +219,7 @@ type connection: record { service: set[string]; addl: string; ##< Deprecated. hot: count; ##< Deprecated. - history: string; ##< State history of TCP connections. See *history* in :bro:see:`Conn::Info`. + history: string; ##< State history of connections. See *history* in :bro:see:`Conn::Info`. ## A globally unique connection identifier. For each connection, Bro creates an ID ## that is very likely unique across independent Bro runs. These IDs can thus be ## used to tag and locate information associated with that connection. diff --git a/scripts/base/protocols/conn/main.bro b/scripts/base/protocols/conn/main.bro index 34ec12fa56..c526681f2a 100644 --- a/scripts/base/protocols/conn/main.bro +++ b/scripts/base/protocols/conn/main.bro @@ -68,7 +68,7 @@ export { missed_bytes: count &log &default=0; ## Records the state history of connections as a string of letters. - ## For TCP connections the meaning of those letters is: + ## The meaning of those letters is: ## ## ====== ==================================================== ## Letter Meaning diff --git a/src/event.bif b/src/event.bif index ded054dd53..e3dcfb6aef 100644 --- a/src/event.bif +++ b/src/event.bif @@ -171,8 +171,11 @@ event new_connection_contents%(c: connection%); ## new_connection new_connection_contents partial_connection event connection_attempt%(c: connection%); -## Generated for an established TCP connection. The event is raised when the -## initial 3-way TCP handshake has successfully finished for a connection. +## Generated when a SYN-ACK packet is seen in response to SYN a packet during +## a TCP handshake. The final ACK of the handshake in response to SYN-ACK may +## or may not occur later, one way to tell is to check the *history* field of +## :bro:type:`connection` to see if the originator sent an ACK, indicated by +## 'A' in the history string. ## ## c: The connection. ## @@ -335,8 +338,6 @@ event connection_SYN_packet%(c: connection, pkt: SYN_packet%); ## ## c: The connection. ## -## pkt: Information extracted from the SYN packet. -## ## .. bro:see:: connection_EOF connection_SYN_packet connection_attempt ## connection_established connection_external connection_finished ## connection_half_finished connection_partial_close connection_pending From aaa16133a7ddb8c3f960dd4e08d27d27eae79e08 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 24 May 2012 16:48:15 -0700 Subject: [PATCH 10/15] Make tests even quieter. --- testing/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/Makefile b/testing/Makefile index 1c82580ec4..c4a2aeddda 100644 --- a/testing/Makefile +++ b/testing/Makefile @@ -6,10 +6,10 @@ all: make-verbose coverage brief: make-brief coverage make-verbose: - @for repo in $(DIRS); do (cd $$repo && make ); done + @for repo in $(DIRS); do (cd $$repo && make -s ); done make-brief: - @for repo in $(DIRS); do (cd $$repo && make brief ); done + @for repo in $(DIRS); do (cd $$repo && make -s brief ); done coverage: @for repo in $(DIRS); do (cd $$repo && echo "Coverage for '$$repo' dir:" && make coverage); done From 2933961042fc6a586de23e4f1d13578e74e359e9 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 24 May 2012 16:48:28 -0700 Subject: [PATCH 11/15] Updating submodule(s). [nomail] --- aux/btest | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/aux/btest b/aux/btest index e0da8d0e28..3ee8d4b323 160000 --- a/aux/btest +++ b/aux/btest @@ -1 +1 @@ -Subproject commit e0da8d0e284bbebbaef711c91c1b961580f225d2 +Subproject commit 3ee8d4b3232d74ed7bd475819193ad3a4055e2f5 From d2c756cac43f0fbaa2ac05844ab68c245c47e6a7 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 24 May 2012 17:33:02 -0700 Subject: [PATCH 12/15] Make tests even quieter. --- testing/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/Makefile b/testing/Makefile index c4a2aeddda..d56ee4e0e1 100644 --- a/testing/Makefile +++ b/testing/Makefile @@ -12,7 +12,7 @@ make-brief: @for repo in $(DIRS); do (cd $$repo && make -s brief ); done coverage: - @for repo in $(DIRS); do (cd $$repo && echo "Coverage for '$$repo' dir:" && make coverage); done + @for repo in $(DIRS); do (cd $$repo && echo "Coverage for '$$repo' dir:" && make -s coverage); done @test -f btest/coverage.log && cp btest/coverage.log `mktemp brocov.tmp.XXX` || true @for f in external/*/coverage.log; do test -f $$f && cp $$f `mktemp brocov.tmp.XXX` || true; done @echo "Complete test suite code coverage:" From 3d2009cacfda99acefd16ed64c5e5f8da4f43d10 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Thu, 24 May 2012 17:43:35 -0700 Subject: [PATCH 13/15] Updating submodule(s). [nomail] --- aux/broccoli | 2 +- aux/broctl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/aux/broccoli b/aux/broccoli index 95c93494d7..07866915a1 160000 --- a/aux/broccoli +++ b/aux/broccoli @@ -1 +1 @@ -Subproject commit 95c93494d7192f69d30f208c4caa3bd38adda6fd +Subproject commit 07866915a1450ddd25b888917f494b4824b0cc3f diff --git a/aux/broctl b/aux/broctl index ba9e1aa2f2..892b60edb9 160000 --- a/aux/broctl +++ b/aux/broctl @@ -1 +1 @@ -Subproject commit ba9e1aa2f2159deac0cf96863f54405643764df0 +Subproject commit 892b60edb967bb456872638f22ba994e84530137 From b5417a32be4cfe4babdf26f942b3b2b84e785781 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 25 May 2012 08:31:06 -0700 Subject: [PATCH 14/15] Some tweaks to the DS doc. Also including a section with deficiencies. --- doc/logging-dataseries.rst | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/doc/logging-dataseries.rst b/doc/logging-dataseries.rst index b41b9fb0b7..554600f055 100644 --- a/doc/logging-dataseries.rst +++ b/doc/logging-dataseries.rst @@ -6,8 +6,8 @@ Binary Output with DataSeries .. rst-class:: opening Bro's default ASCII log format is not exactly the most efficient - way for storing large volumes of data. An an alternative, Bro comes - with experimental support for `DataSeries + way for storing and searching large volumes of data. An an + alternative, Bro comes with experimental support for `DataSeries `_ output, an efficient binary format for recording structured bulk data. DataSeries is developed and maintained at HP Labs. @@ -35,9 +35,12 @@ To build and install the two into ````, do:: Please refer to the packages' documentation for more information about the installation process. In particular, there's more information on required and optional `dependencies for Lintel -`_ +`_ and `dependencies for DataSeries -`_ +`_. +For users on RedHat-style systems, you'll need the following:: + + yum install libxml2-devel boost-devel Compiling Bro with DataSeries Support ------------------------------------- @@ -166,3 +169,18 @@ with the output files. The ``man`` pages for these tool show further options, and their ``-h`` option gives some more information (either can be a bit cryptic unfortunately though). + +Deficiencies +------------ + +Due to limitations of the DataSeries format, one cannot inspect its +files before they have been fully written. In other words, when using +DataSeries, it's currently it's not possible to inspect the live log +files inside the spool directory before they are rotated to their +final location. It seems that this could be fixed with some effort, +and we will work with DataSeries development team on that if the +format gains traction among Bro users. + +Likewise, we're considering writing custom command line tools for +interacting with DataSeries files, making that a bit more convenient +than what the standard utilities provide. From da34266a526eb08f757fe4a6a7bf61fbdb82a3d6 Mon Sep 17 00:00:00 2001 From: Robin Sommer Date: Fri, 25 May 2012 08:36:36 -0700 Subject: [PATCH 15/15] Switching default DS compression to gzip. --- scripts/base/frameworks/logging/writers/dataseries.bro | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/base/frameworks/logging/writers/dataseries.bro b/scripts/base/frameworks/logging/writers/dataseries.bro index ccee500c3a..e85d9c8c49 100644 --- a/scripts/base/frameworks/logging/writers/dataseries.bro +++ b/scripts/base/frameworks/logging/writers/dataseries.bro @@ -10,7 +10,7 @@ export { ## 'lzo' -- LZO compression. Very fast decompression times. ## 'gz' -- GZIP compression. Slower than LZF, but also produces smaller output. ## 'bz2' -- BZIP2 compression. Slower than GZIP, but also produces smaller output. - const compression = "lzo" &redef; + const compression = "gz" &redef; ## The extent buffer size. ## Larger values here lead to better compression and more efficient writes, but