From: William Lallemand Date: Fri, 2 Mar 2012 13:35:21 +0000 (+0100) Subject: MEDIUM: log-format: backend source address %Bi %Bp X-Git-Tag: v1.5-dev8~11 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b7ff6a3a36658d7c829de626beea6df80c79a3cb;p=thirdparty%2Fhaproxy.git MEDIUM: log-format: backend source address %Bi %Bp %Bi return the backend source IP %Bp return the backend source port Add a function pointer in logformat_type to do additional configuration during the log-format variable parsing. --- diff --git a/doc/configuration.txt b/doc/configuration.txt index 70a25391e7..58ceebbe87 100644 --- a/doc/configuration.txt +++ b/doc/configuration.txt @@ -8790,6 +8790,8 @@ Please refer to the table below for currently defined variables : | | %B | bytes_read | numeric | | | %Ci | client_ip | string | | | %Cp | client_port | numeric | + | | %Bi | backend_source_ip | string | + | | %Bp | backend_source_port | numeric | | | %Tc | Tc | numeric | | * | %Tq | Tq | numeric | | * | %Tr | Tr | numeric | diff --git a/include/types/log.h b/include/types/log.h index 0e78024116..2f11aabb7f 100644 --- a/include/types/log.h +++ b/include/types/log.h @@ -44,6 +44,8 @@ enum { LOG_GLOBAL, LOG_CLIENTIP, LOG_CLIENTPORT, + LOG_SOURCEPORT, + LOG_SOURCEIP, LOG_DATE, LOG_DATEGMT, LOG_MS, diff --git a/include/types/proxy.h b/include/types/proxy.h index 6693d8288d..26cdfe4650 100644 --- a/include/types/proxy.h +++ b/include/types/proxy.h @@ -138,7 +138,9 @@ enum { #define PR_O2_NODELAY 0x00020000 /* fully interactive mode, never delay outgoing data */ #define PR_O2_USE_PXHDR 0x00040000 /* use Proxy-Connection for proxy requests */ #define PR_O2_CHK_SNDST 0x00080000 /* send the state of each server along with HTTP health checks */ -/* unused: 0x00100000 */ + +#define PR_O2_SRC_ADDR 0x00100000 /* get the source ip and port for logs */ + #define PR_O2_FAKE_KA 0x00200000 /* pretend we do keep-alive with server eventhough we close */ /* unused: 0x00400000 */ #define PR_O2_EXP_NONE 0x00000000 /* http-check : no expect rule */ diff --git a/include/types/session.h b/include/types/session.h index a707aa52e1..5678e5c069 100644 --- a/include/types/session.h +++ b/include/types/session.h @@ -84,6 +84,7 @@ #define SN_IGNORE_PRST 0x00080000 /* ignore persistence */ #define SN_BE_TRACK_SC1 0x00100000 /* backend tracks stick-counter 1 */ #define SN_BE_TRACK_SC2 0x00200000 /* backend tracks stick-counter 2 */ +#define SN_BCK_ADDR_SET 0x00400000 /* set if the backend address has been filled */ /* Termination sequence tracing. * diff --git a/include/types/stream_interface.h b/include/types/stream_interface.h index 4f0bfa2d25..5acbd5743c 100644 --- a/include/types/stream_interface.h +++ b/include/types/stream_interface.h @@ -72,6 +72,7 @@ enum { SI_FL_DONT_WAKE = 0x0020, /* resync in progress, don't wake up */ SI_FL_INDEP_STR = 0x0040, /* independant streams = don't update rex on write */ SI_FL_NOLINGER = 0x0080, /* may close without lingering. One-shot. */ + SI_FL_SRC_ADDR = 0x1000, /* get the source ip/port with getsockname */ }; /* target types */ diff --git a/src/backend.c b/src/backend.c index 32eea68b4c..39ee58bce7 100644 --- a/src/backend.c +++ b/src/backend.c @@ -985,6 +985,10 @@ int connect_server(struct session *s) assign_tproxy_address(s); + /* flag for logging source ip/port */ + if (s->fe->options2 & PR_O2_SRC_ADDR) + s->req->cons->flags |= SI_FL_SRC_ADDR; + err = s->req->cons->connect(s->req->cons); if (err != SN_ERR_NONE) diff --git a/src/log.c b/src/log.c index 3bcfaa56b9..e129c2d12f 100644 --- a/src/log.c +++ b/src/log.c @@ -57,42 +57,47 @@ struct logformat_type { char *name; int type; int mode; + int (*config_callback)(struct logformat_node *node, struct proxy *curproxy); }; +int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy); + /* log_format variable names */ static const struct logformat_type logformat_keywords[] = { - { "o", LOG_GLOBAL, PR_MODE_TCP }, /* global option */ - { "Ci", LOG_CLIENTIP, PR_MODE_TCP }, /* client ip */ - { "Cp", LOG_CLIENTPORT, PR_MODE_TCP }, /* client port */ - { "t", LOG_DATE, PR_MODE_TCP }, /* date */ - { "T", LOG_DATEGMT, PR_MODE_TCP }, /* date GMT */ - { "ms", LOG_MS, PR_MODE_TCP }, /* accept date millisecond */ - { "f", LOG_FRONTEND, PR_MODE_TCP }, /* frontend */ - { "b", LOG_BACKEND, PR_MODE_TCP }, /* backend */ - { "s", LOG_SERVER, PR_MODE_TCP }, /* server */ - { "B", LOG_BYTES, PR_MODE_TCP }, /* bytes read */ - { "Tq", LOG_TQ, PR_MODE_HTTP }, /* Tq */ - { "Tw", LOG_TW, PR_MODE_TCP }, /* Tw */ - { "Tc", LOG_TC, PR_MODE_TCP }, /* Tc */ - { "Tr", LOG_TR, PR_MODE_HTTP }, /* Tr */ - { "Tt", LOG_TT, PR_MODE_TCP }, /* Tt */ - { "st", LOG_STATUS, PR_MODE_HTTP }, /* status code */ - { "cc", LOG_CCLIENT, PR_MODE_HTTP }, /* client cookie */ - { "cs", LOG_CSERVER, PR_MODE_HTTP }, /* server cookie */ - { "ts", LOG_TERMSTATE, PR_MODE_TCP },/* terminaison state */ - { "ac", LOG_ACTCONN, PR_MODE_TCP }, /* actconn */ - { "fc", LOG_FECONN, PR_MODE_TCP }, /* feconn */ - { "bc", LOG_BECONN, PR_MODE_TCP }, /* beconn */ - { "sc", LOG_SRVCONN, PR_MODE_TCP }, /* srv_conn */ - { "rc", LOG_RETRIES, PR_MODE_TCP }, /* retries */ - { "sq", LOG_SRVQUEUE, PR_MODE_TCP }, /* srv_queue */ - { "bq", LOG_BCKQUEUE, PR_MODE_TCP }, /* backend_queue */ - { "hr", LOG_HDRREQUEST, PR_MODE_HTTP }, /* header request */ - { "hs", LOG_HDRRESPONS, PR_MODE_HTTP }, /* header response */ - { "hrl", LOG_HDRREQUESTLIST, PR_MODE_HTTP }, /* header request list */ - { "hsl", LOG_HDRRESPONSLIST, PR_MODE_HTTP }, /* header response list */ - { "r", LOG_REQ, PR_MODE_HTTP }, /* request */ - { 0, 0 } + { "o", LOG_GLOBAL, PR_MODE_TCP, NULL }, /* global option */ + { "Ci", LOG_CLIENTIP, PR_MODE_TCP, NULL }, /* client ip */ + { "Cp", LOG_CLIENTPORT, PR_MODE_TCP, NULL }, /* client port */ + { "Bp", LOG_SOURCEPORT, PR_MODE_TCP, prepare_addrsource }, /* backend source port */ + { "Bi", LOG_SOURCEIP, PR_MODE_TCP, prepare_addrsource }, /* backend source ip */ + { "t", LOG_DATE, PR_MODE_TCP, NULL }, /* date */ + { "T", LOG_DATEGMT, PR_MODE_TCP, NULL }, /* date GMT */ + { "ms", LOG_MS, PR_MODE_TCP, NULL }, /* accept date millisecond */ + { "f", LOG_FRONTEND, PR_MODE_TCP, NULL }, /* frontend */ + { "b", LOG_BACKEND, PR_MODE_TCP, NULL }, /* backend */ + { "s", LOG_SERVER, PR_MODE_TCP, NULL }, /* server */ + { "B", LOG_BYTES, PR_MODE_TCP, NULL }, /* bytes read */ + { "Tq", LOG_TQ, PR_MODE_HTTP, NULL }, /* Tq */ + { "Tw", LOG_TW, PR_MODE_TCP, NULL }, /* Tw */ + { "Tc", LOG_TC, PR_MODE_TCP, NULL }, /* Tc */ + { "Tr", LOG_TR, PR_MODE_HTTP, NULL }, /* Tr */ + { "Tt", LOG_TT, PR_MODE_TCP, NULL }, /* Tt */ + { "st", LOG_STATUS, PR_MODE_HTTP, NULL }, /* status code */ + { "cc", LOG_CCLIENT, PR_MODE_HTTP, NULL }, /* client cookie */ + { "cs", LOG_CSERVER, PR_MODE_HTTP, NULL }, /* server cookie */ + { "ts", LOG_TERMSTATE, PR_MODE_TCP, NULL },/* terminaison state */ + { "ac", LOG_ACTCONN, PR_MODE_TCP, NULL }, /* actconn */ + { "fc", LOG_FECONN, PR_MODE_TCP, NULL }, /* feconn */ + { "bc", LOG_BECONN, PR_MODE_TCP, NULL }, /* beconn */ + { "sc", LOG_SRVCONN, PR_MODE_TCP, NULL }, /* srv_conn */ + { "rc", LOG_RETRIES, PR_MODE_TCP, NULL }, /* retries */ + { "sq", LOG_SRVQUEUE, PR_MODE_TCP, NULL }, /* srv_queue */ + { "bq", LOG_BCKQUEUE, PR_MODE_TCP, NULL }, /* backend_queue */ + { "hr", LOG_HDRREQUEST, PR_MODE_HTTP, NULL }, /* header request */ + { "hs", LOG_HDRRESPONS, PR_MODE_HTTP, NULL }, /* header response */ + { "hrl", LOG_HDRREQUESTLIST, PR_MODE_HTTP, NULL }, /* header request list */ + { "hsl", LOG_HDRRESPONSLIST, PR_MODE_HTTP, NULL }, /* header response list */ + { "r", LOG_REQ, PR_MODE_HTTP, NULL }, /* request */ + { 0, 0, 0, NULL } }; char default_http_log_format[] = "%Ci:%Cp [%t] %f %b/%s %Tq/%Tw/%Tc/%Tr/%Tt %st %B %cc %cs %ts %ac/%fc/%bc/%sc/%rc %sq/%bq %hr %hs %{+Q}r"; // default format @@ -112,6 +117,17 @@ struct logformat_var_args var_args_list[] = { { 0, 0 } }; +/* + * callback used to configure addr source retrieval + */ +int prepare_addrsource(struct logformat_node *node, struct proxy *curproxy) +{ + curproxy->options2 |= PR_O2_SRC_ADDR; + + return 0; +} + + /* * Parse args in a logformat_var */ @@ -201,6 +217,11 @@ int parse_logformat_var(char *str, size_t len, struct proxy *curproxy) logformat_options = node->options; free(node); } else { + if (logformat_keywords[j].config_callback != NULL) { + if (logformat_keywords[j].config_callback(node, curproxy) != 0) { + return -1; + } + } LIST_ADDQ(&curproxy->logformat, &node->list); } return 0; @@ -678,6 +699,7 @@ const char sess_set_cookie[8] = "NPDIRU67"; /* No set-cookie, Set-cookie found a void sess_log(struct session *s) { char pn[INET6_ADDRSTRLEN]; + char sn[INET6_ADDRSTRLEN]; struct proxy *fe = s->fe; struct proxy *be = s->be; struct proxy *prx_log; @@ -707,6 +729,11 @@ void sess_log(struct session *s) if (addr_to_str(&s->req->prod->addr.from, pn, sizeof(pn)) == AF_UNIX) snprintf(pn, sizeof(pn), "unix:%d", s->listener->luid); + if (be->options2 & PR_O2_SRC_ADDR) { + if (addr_to_str(&s->req->cons->addr.from, sn, sizeof(sn)) == AF_UNIX) + snprintf(sn, sizeof(sn), "unix:%d", s->listener->luid); + } + /* FIXME: let's limit ourselves to frontend logging for now. */ tolog = fe->to_log; @@ -774,6 +801,23 @@ void sess_log(struct session *s) last_isspace = 0; break; + case LOG_SOURCEIP: // Bi + src = (s->req->cons->addr.from.ss_family == AF_UNIX) ? "unix" : sn; + tmplog = logformat_write_string(tmplog, src, MAX_SYSLOG_LEN - (tmplog - logline), tmp); + + if (!tmplog) + goto out; + last_isspace = 0; + break; + + case LOG_SOURCEPORT: // %Bp + tmplog = ltoa_o((s->req->cons->addr.from.ss_family == AF_UNIX) ? s->listener->luid : get_host_port(&s->req->cons->addr.from), + tmplog, MAX_SYSLOG_LEN - (tmplog - logline)); + if (!tmplog) + goto out; + last_isspace = 0; + break; + case LOG_DATE: // %t get_localtime(s->logs.accept_date.tv_sec, &tm); tmplog = date2str_log(tmplog, &tm, &(s->logs.accept_date), MAX_SYSLOG_LEN - (tmplog - logline)); diff --git a/src/proto_tcp.c b/src/proto_tcp.c index ea3692cbbc..80f1e36eb0 100644 --- a/src/proto_tcp.c +++ b/src/proto_tcp.c @@ -437,6 +437,14 @@ int tcp_connect_server(struct stream_interface *si) } } + /* needs src ip/port for logging */ + if (si->flags & SI_FL_SRC_ADDR) { + socklen_t addrlen = sizeof(si->addr.to); + if (getsockname(fd, (struct sockaddr *)&si->addr.from, &addrlen) == -1) { + Warning("Cannot get source address for logging.\n"); + } + } + fdtab[fd].owner = si; fdtab[fd].state = FD_STCONN; /* connection in progress */ fdtab[fd].flags = FD_FL_TCP | FD_FL_TCP_NODELAY;