libnetmon.h 8.44 KB
Newer Older
1
/*
2
 * Copyright (c) 2006-2007 University of Utah and the Flux Group.
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
 * 
 * {{{EMULAB-LICENSE
 * 
 * This file is part of the Emulab network testbed software.
 * 
 * This file is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at
 * your option) any later version.
 * 
 * This file is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
 * License for more details.
 * 
 * You should have received a copy of the GNU Affero General Public License
 * along with this file.  If not, see <http://www.gnu.org/licenses/>.
 * 
 * }}}
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
 *
 * Header for libnetmon, a library for monitoring network traffic sent by a
 * process. See README for instructions.
 */

#ifdef __linux__
/* Needed to get RTLD_NEXT on Linux */
#define _GNU_SOURCE
#endif

#include <sys/types.h>
#include <dlfcn.h>
#include <stdarg.h>
#include <sys/param.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <strings.h>
42
#include <string.h>
43 44
#include <sys/time.h>
#include <sys/socket.h>
45
#include <netinet/in.h>
46
#include <netinet/tcp.h>
47
#include <arpa/inet.h>
48
#include <sys/un.h>
49 50 51
#include <unistd.h>

#include "netmon.h"
52

53
// #define DEBUGGING
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71

#ifdef DEBUGGING
#define DEBUG(x) (x)
#else
#define DEBUG(x)
#endif

/*
 * Just a few things for convience
 */
const unsigned int FD_ALLOC_SIZE = 8;

/*
 * Initialization for the library - dies if initialization fails. Safe to call
 * more than once, just skips intialization if it's already been done.
 */
static void lnm_init();

72 73 74 75 76 77 78 79 80 81
/*
 * Handle packets on the control socket, if any
 */
static void lnm_control();

/*
 * Wait for a control message, then process it
 */
static void lnm_control_wait();

82 83 84 85 86
/*
 * Parse a list of reports
 */
static void lnm_parse_reportopt(char *s);

87 88 89 90 91 92
/*
 * Allocate space for the monitorFDs - increases the allocation by
 * FD_ALLOC_SIZE slots.
 */
static void allocFDspace();

93 94 95 96 97 98
/*
 * Make sure there's enough room for the given FD in the file descriptor
 * table
 */
static void allocFDspaceFor(int);

99 100 101 102 103
/*
 * Predicate function: Are we monitoring this file descriptor?
 */
static bool monitorFD_p(int);

104 105 106 107 108
/*
 * Predicate funtion: Is this file descriptor connected?
 */
static bool connectedFD_p(int);

109 110 111 112 113 114 115 116 117
/*
 * Logging messages
 */

/*
 * The types of log messages which are currently defined, and the associated
 * ASCII strings
 */
typedef enum { LOG_NEW = 0,
118
               LOG_REMOTEIP,
119 120 121 122 123 124 125
               LOG_REMOTEPORT,
               LOG_LOCALPORT,
               LOG_TCP_NODELAY,
               LOG_TCP_MAXSEG,
               LOG_SO_RCVBUF,
               LOG_SO_SNDBUF,
               LOG_CONNECTED,
126
               LOG_ACCEPTED,
127 128
               LOG_SEND,
               LOG_SENDTO,
129 130 131 132
               LOG_CLOSED,
               LOG_INIT,
               LOG_EXIT,
               LOG_SENDMSG
133 134 135 136 137 138 139 140 141 142 143
} logmsg_t;
static char *log_type_names[] = {
    "New",
    "RemoteIP",
    "RemotePort",
    "LocalPort",
    "TCP_NODELAY",
    "TCP_MAXSEG",
    "SO_RCVBUF",
    "SO_SNDBUF",
    "Connected",
144
    "Accepted",
145 146
    "Send",
    "SendTo",
147 148 149 150
    "Closed",
    "Init",
    "Exit",
    "SendMsg"
151 152 153 154 155 156 157 158 159 160
};

/*
 * Print out a log message. First argument is the type of the log mesage, the
 * second is the file descriptor number, and the remaining arguments are
 * processed like arguments to printf() (ie. a format string, then zero or more
 * arguments to be interpolated into the format string)
 */
static void printlog(logmsg_t,int, ... );

161 162 163 164 165 166
/*
 * A constant passed to printlog() to indicate that there is no file descriptor
 * associated with this message
 */
static int NO_FD = -42;

167 168
/*
 * Log that a packet has been sent to the kernel on a given FD with a given
169 170
 * size. If the final argument is non-NULL, then we are logging a packet from
 * sendto(), and should report the IP address and port numbers involved
171
 */
172
static void log_packet(int, size_t, const struct sockaddr*);
173

174 175 176
/*
 * The information we keep about each FD we're monitoring
 */
177
typedef struct {
178
    bool monitoring;
179 180 181 182 183 184
//    char *remote_hostname; /* We keep the char* so that we don't have to
//                              convert every time we want to report */
    struct in_addr remote_hostname; /* We keep this as an in_addr
                                       because inet_ntoa is not
                                       re-entrant and uses static
                                       memory for its result. */
185
    int remote_port;
186
    int local_port;
187 188 189

    bool connected; /* Is this FD currently connected or not? */

190 191
    int socktype; /* Socket type - normally SOCK_STREAM or SOCK_DGRAM */

192 193 194 195 196 197 198 199
    /*
     * Socket options we keep track of
     */
    int sndbuf;
    int rcvbuf;
    bool tcp_nodelay;
    int tcp_maxseg;

200

201 202
} fdRecord;

203 204 205
/*
 * List of which file descriptors we're monitoring
 */
206
static fdRecord* monitorFDs;
207 208
static unsigned int fdSize;

209 210 211 212 213
/*
 * Find out what size socket buffer the kernel just gave us
 */
static int getNewSockbuf(int,int);

214 215 216
/*
 * Stream on which to write reports
 */
217 218 219 220 221 222
static FILE *outstream;

/*
 * File descriptor for the control socket - < 0 if we have none
 */
static int controlfd;
223

224 225 226
/*
 * Force the socket buffer size
 */
227 228 229 230 231 232
static int forced_bufsize;

/*
 * Give a maximum socket buffer size
 */
static int max_bufsize;
233

234 235 236
/*
 * Manipulate the monitorFDs structure
 */
237 238
static void startFD(int);
static void nameFD(int, const struct sockaddr *, const struct sockaddr *);
239
static void stopFD(int);
240
static void stopWatchingAll();
241

242 243 244 245 246
/*
 * Print unique identifier for an FD
 */
static void fprintID(FILE *, int);

247 248 249 250 251
/*
 * Print out the current time in standard format
 */
void fprintTime(FILE *);

252 253 254 255 256 257 258 259 260 261
/*
 * Process a packet from the control socket
 */
static void process_control_packet(generic_m *);

/*
 * Sed out a query on the control socket
 */
static void control_query();

262 263 264 265 266
/*
 * Which version of the output format are we using?
 */
static unsigned int output_version;

267 268 269 270 271 272 273 274 275 276 277 278
/*
 * Our PID
 */
static pid_t pid;

/*
 * These describe the types of sockets we're monitoring - basically, are we
 * monitoring TCP, UDP, or both?
 */
static bool monitor_tcp;
static bool monitor_udp;

279 280 281 282 283 284 285 286 287 288
/*
 * These describe which things we need to report on. report_all is sort of a
 * meta-option - at the end of initialization, if it's set, we turn on the
 * rest of the options, but it's not used after that. This is to cut down
 * on the number of places we have to remember all of them...
 */
static bool report_all;
static bool report_io;
static bool report_sockopt;
static bool report_connect;
289
static bool report_init;
290

291 292 293 294 295 296
/*
 * Prototypes for the real library functions - just makes it easier to declare
 * function pointers for them.
 */
typedef int open_proto_t(const char *, int, ...);
typedef int stat_proto_t(const char *, struct stat *sb);
297
typedef int socket_proto_t(int, int,int);
298 299 300 301
typedef int close_proto_t(int);
typedef int connect_proto_t(int, const struct sockaddr*, socklen_t);
typedef ssize_t write_proto_t(int, const void *, size_t);
typedef ssize_t send_proto_t(int, const void *, ssize_t, int);
302
typedef int setsockopt_proto_t(int, int, int, const void*, socklen_t);
303 304
typedef ssize_t read_proto_t(int, void *, size_t);
typedef ssize_t recv_proto_t(int, void *, size_t, int);
305 306
typedef ssize_t recvmsg_proto_t(int, struct msghdr *, int);
typedef ssize_t accept_proto_t(int, struct sockaddr *, socklen_t *);
307
typedef ssize_t sendto_proto_t(int, const void *, size_t, int,
308
                               const struct sockaddr *, socklen_t);
309
typedef ssize_t sendmsg_proto_t(int, const struct msghdr *, int);
310 311 312 313

/*
 * Locations of the real library functions
 */
314 315 316 317 318
static socket_proto_t     *real_socket;
static close_proto_t      *real_close;
static connect_proto_t    *real_connect;
static write_proto_t      *real_write;
static send_proto_t       *real_send;
319
static setsockopt_proto_t *real_setsockopt;
320 321 322 323
static read_proto_t       *real_read;
static recv_proto_t       *real_recv;
static recvmsg_proto_t    *real_recvmsg;
static accept_proto_t     *real_accept;
324
static sendto_proto_t     *real_sendto;
325
static sendmsg_proto_t    *real_sendmsg;
326 327 328 329

/*
 * Note: Functions that we're wrapping are in the .c file
 */
330 331 332 333 334 335 336

/*
 * Functions we use to inform the user about various events
 */
static void informNodelay(int);
static void informMaxseg(int);
static void informBufsize(int, int);
337 338
typedef enum {INFORM_CONNECT, INFORM_ACCEPT} inform_which_t;
static void informConnect(int,inform_which_t);