blob: 3c7b63a62022bb3c999683c0d948cc323d4d6478 [file] [log] [blame]
Vladimir Homutov493b8982014-05-12 16:34:15 +04001
2/*
3 * Copyright (C) Nginx, Inc.
4 */
5
6
7#include <ngx_config.h>
8#include <ngx_core.h>
9#include <ngx_event.h>
10
11
12#define NGX_SYSLOG_MAX_STR \
Ruslan Ermilov2161d8a2016-03-30 11:52:16 +030013 NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1 \
14 + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */ \
15 + 32 /* tag */ + 2 /* colon, space */
Vladimir Homutov493b8982014-05-12 16:34:15 +040016
17
18static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
19static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer);
20static void ngx_syslog_cleanup(void *data);
21
22
23static char *facilities[] = {
24 "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp",
25 "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0",
26 "local1", "local2", "local3", "local4", "local5", "local6", "local7",
27 NULL
28};
29
30/* note 'error/warn' like in nginx.conf, not 'err/warning' */
31static char *severities[] = {
32 "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL
33};
34
35static ngx_log_t ngx_syslog_dummy_log;
36static ngx_event_t ngx_syslog_dummy_event;
37
38
39char *
40ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
41{
Vladimir Homutova91a99d2018-05-14 22:50:57 +030042 ngx_pool_cleanup_t *cln;
43
Vladimir Homutov493b8982014-05-12 16:34:15 +040044 peer->facility = NGX_CONF_UNSET_UINT;
45 peer->severity = NGX_CONF_UNSET_UINT;
46
47 if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) {
48 return NGX_CONF_ERROR;
49 }
50
51 if (peer->server.sockaddr == NULL) {
52 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
53 "no syslog server specified");
54 return NGX_CONF_ERROR;
55 }
56
57 if (peer->facility == NGX_CONF_UNSET_UINT) {
58 peer->facility = 23; /* local7 */
59 }
60
61 if (peer->severity == NGX_CONF_UNSET_UINT) {
62 peer->severity = 6; /* info */
63 }
64
65 if (peer->tag.data == NULL) {
66 ngx_str_set(&peer->tag, "nginx");
67 }
68
69 peer->conn.fd = (ngx_socket_t) -1;
70
Vladimir Homutova91a99d2018-05-14 22:50:57 +030071 peer->conn.read = &ngx_syslog_dummy_event;
72 peer->conn.write = &ngx_syslog_dummy_event;
73
74 ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log;
75
76 cln = ngx_pool_cleanup_add(cf->pool, 0);
77 if (cln == NULL) {
78 return NGX_CONF_ERROR;
79 }
80
81 cln->data = peer;
82 cln->handler = ngx_syslog_cleanup;
83
Vladimir Homutov493b8982014-05-12 16:34:15 +040084 return NGX_CONF_OK;
85}
86
87
88static char *
89ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
90{
91 u_char *p, *comma, c;
92 size_t len;
93 ngx_str_t *value;
94 ngx_url_t u;
95 ngx_uint_t i;
96
97 value = cf->args->elts;
98
99 p = value[1].data + sizeof("syslog:") - 1;
100
101 for ( ;; ) {
102 comma = (u_char *) ngx_strchr(p, ',');
103
104 if (comma != NULL) {
105 len = comma - p;
106 *comma = '\0';
107
108 } else {
109 len = value[1].data + value[1].len - p;
110 }
111
112 if (ngx_strncmp(p, "server=", 7) == 0) {
113
114 if (peer->server.sockaddr != NULL) {
115 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
116 "duplicate syslog \"server\"");
117 return NGX_CONF_ERROR;
118 }
119
120 ngx_memzero(&u, sizeof(ngx_url_t));
121
122 u.url.data = p + 7;
123 u.url.len = len - 7;
124 u.default_port = 514;
125
126 if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
127 if (u.err) {
128 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
129 "%s in syslog server \"%V\"",
130 u.err, &u.url);
131 }
132
133 return NGX_CONF_ERROR;
134 }
135
136 peer->server = u.addrs[0];
137
138 } else if (ngx_strncmp(p, "facility=", 9) == 0) {
139
140 if (peer->facility != NGX_CONF_UNSET_UINT) {
141 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
142 "duplicate syslog \"facility\"");
143 return NGX_CONF_ERROR;
144 }
145
146 for (i = 0; facilities[i] != NULL; i++) {
147
148 if (ngx_strcmp(p + 9, facilities[i]) == 0) {
149 peer->facility = i;
150 goto next;
151 }
152 }
153
154 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
155 "unknown syslog facility \"%s\"", p + 9);
156 return NGX_CONF_ERROR;
157
158 } else if (ngx_strncmp(p, "severity=", 9) == 0) {
159
160 if (peer->severity != NGX_CONF_UNSET_UINT) {
161 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
162 "duplicate syslog \"severity\"");
163 return NGX_CONF_ERROR;
164 }
165
166 for (i = 0; severities[i] != NULL; i++) {
167
168 if (ngx_strcmp(p + 9, severities[i]) == 0) {
169 peer->severity = i;
170 goto next;
171 }
172 }
173
174 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
175 "unknown syslog severity \"%s\"", p + 9);
176 return NGX_CONF_ERROR;
177
178 } else if (ngx_strncmp(p, "tag=", 4) == 0) {
179
180 if (peer->tag.data != NULL) {
181 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
182 "duplicate syslog \"tag\"");
183 return NGX_CONF_ERROR;
184 }
185
186 /*
187 * RFC 3164: the TAG is a string of ABNF alphanumeric characters
188 * that MUST NOT exceed 32 characters.
189 */
190 if (len - 4 > 32) {
191 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
192 "syslog tag length exceeds 32");
193 return NGX_CONF_ERROR;
194 }
195
196 for (i = 4; i < len; i++) {
197 c = ngx_tolower(p[i]);
198
Vladimir Homutov742b5dd2014-11-20 20:02:21 +0300199 if (c < '0' || (c > '9' && c < 'a' && c != '_') || c > 'z') {
Vladimir Homutov493b8982014-05-12 16:34:15 +0400200 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
201 "syslog \"tag\" only allows "
Vladimir Homutov742b5dd2014-11-20 20:02:21 +0300202 "alphanumeric characters "
203 "and underscore");
Vladimir Homutov493b8982014-05-12 16:34:15 +0400204 return NGX_CONF_ERROR;
205 }
206 }
207
208 peer->tag.data = p + 4;
209 peer->tag.len = len - 4;
210
Vladimir Homutov73f085f2015-10-26 19:06:42 +0300211 } else if (len == 10 && ngx_strncmp(p, "nohostname", 10) == 0) {
212 peer->nohostname = 1;
213
Vladimir Homutov493b8982014-05-12 16:34:15 +0400214 } else {
215 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
216 "unknown syslog parameter \"%s\"", p);
217 return NGX_CONF_ERROR;
218 }
219
220 next:
221
222 if (comma == NULL) {
223 break;
224 }
225
226 p = comma + 1;
227 }
228
229 return NGX_CONF_OK;
230}
231
232
233u_char *
234ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf)
235{
236 ngx_uint_t pri;
237
238 pri = peer->facility * 8 + peer->severity;
239
Vladimir Homutov73f085f2015-10-26 19:06:42 +0300240 if (peer->nohostname) {
241 return ngx_sprintf(buf, "<%ui>%V %V: ", pri, &ngx_cached_syslog_time,
242 &peer->tag);
243 }
244
Vladimir Homutov493b8982014-05-12 16:34:15 +0400245 return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time,
246 &ngx_cycle->hostname, &peer->tag);
247}
248
249
250void
251ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
252 size_t len)
253{
254 u_char *p, msg[NGX_SYSLOG_MAX_STR];
255 ngx_uint_t head_len;
256 ngx_syslog_peer_t *peer;
257
258 peer = log->wdata;
259
Vladimir Homutovd79cbf12014-09-01 17:55:07 +0400260 if (peer->busy) {
Vladimir Homutov493b8982014-05-12 16:34:15 +0400261 return;
262 }
263
Vladimir Homutovd79cbf12014-09-01 17:55:07 +0400264 peer->busy = 1;
Vladimir Homutov493b8982014-05-12 16:34:15 +0400265 peer->severity = level - 1;
266
267 p = ngx_syslog_add_header(peer, msg);
268 head_len = p - msg;
269
270 len -= NGX_LINEFEED_SIZE;
271
272 if (len > NGX_SYSLOG_MAX_STR - head_len) {
273 len = NGX_SYSLOG_MAX_STR - head_len;
274 }
275
276 p = ngx_snprintf(p, len, "%s", buf);
277
278 (void) ngx_syslog_send(peer, msg, p - msg);
279
Vladimir Homutovd79cbf12014-09-01 17:55:07 +0400280 peer->busy = 0;
Vladimir Homutov493b8982014-05-12 16:34:15 +0400281}
282
283
284ssize_t
285ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len)
286{
Vladimir Homutov27fa3122014-08-26 14:56:54 +0400287 ssize_t n;
288
Vladimir Homutov493b8982014-05-12 16:34:15 +0400289 if (peer->conn.fd == (ngx_socket_t) -1) {
290 if (ngx_syslog_init_peer(peer) != NGX_OK) {
291 return NGX_ERROR;
292 }
293 }
294
Vladimir Homutovd79cbf12014-09-01 17:55:07 +0400295 /* log syslog socket events with valid log */
296 peer->conn.log = ngx_cycle->log;
297
Vladimir Homutov493b8982014-05-12 16:34:15 +0400298 if (ngx_send) {
Vladimir Homutov27fa3122014-08-26 14:56:54 +0400299 n = ngx_send(&peer->conn, buf, len);
Vladimir Homutov493b8982014-05-12 16:34:15 +0400300
301 } else {
302 /* event module has not yet set ngx_io */
Vladimir Homutov27fa3122014-08-26 14:56:54 +0400303 n = ngx_os_io.send(&peer->conn, buf, len);
Vladimir Homutov493b8982014-05-12 16:34:15 +0400304 }
Vladimir Homutov27fa3122014-08-26 14:56:54 +0400305
Vladimir Homutov14e4ddc2018-05-08 19:35:56 +0300306 if (n == NGX_ERROR) {
Vladimir Homutov27fa3122014-08-26 14:56:54 +0400307
308 if (ngx_close_socket(peer->conn.fd) == -1) {
309 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
310 ngx_close_socket_n " failed");
311 }
312
313 peer->conn.fd = (ngx_socket_t) -1;
314 }
315
Vladimir Homutov27fa3122014-08-26 14:56:54 +0400316 return n;
Vladimir Homutov493b8982014-05-12 16:34:15 +0400317}
318
319
320static ngx_int_t
321ngx_syslog_init_peer(ngx_syslog_peer_t *peer)
322{
Vladimir Homutova91a99d2018-05-14 22:50:57 +0300323 ngx_socket_t fd;
Vladimir Homutov493b8982014-05-12 16:34:15 +0400324
Vladimir Homutov493b8982014-05-12 16:34:15 +0400325 fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0);
326 if (fd == (ngx_socket_t) -1) {
327 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
328 ngx_socket_n " failed");
329 return NGX_ERROR;
330 }
331
332 if (ngx_nonblocking(fd) == -1) {
333 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
334 ngx_nonblocking_n " failed");
Vladimir Homutov8e82f062014-05-26 23:34:44 +0400335 goto failed;
Vladimir Homutov493b8982014-05-12 16:34:15 +0400336 }
337
338 if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) {
339 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
340 "connect() failed");
Vladimir Homutov8e82f062014-05-26 23:34:44 +0400341 goto failed;
Vladimir Homutov493b8982014-05-12 16:34:15 +0400342 }
343
344 peer->conn.fd = fd;
Vladimir Homutov21655ae2014-05-27 15:42:34 +0400345
346 /* UDP sockets are always ready to write */
347 peer->conn.write->ready = 1;
348
Vladimir Homutov493b8982014-05-12 16:34:15 +0400349 return NGX_OK;
Vladimir Homutov8e82f062014-05-26 23:34:44 +0400350
351failed:
352
353 if (ngx_close_socket(fd) == -1) {
354 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
355 ngx_close_socket_n " failed");
356 }
357
358 return NGX_ERROR;
Vladimir Homutov493b8982014-05-12 16:34:15 +0400359}
360
361
362static void
363ngx_syslog_cleanup(void *data)
364{
365 ngx_syslog_peer_t *peer = data;
366
Vladimir Homutovd79cbf12014-09-01 17:55:07 +0400367 /* prevents further use of this peer */
368 peer->busy = 1;
369
Vladimir Homutov27fa3122014-08-26 14:56:54 +0400370 if (peer->conn.fd == (ngx_socket_t) -1) {
371 return;
372 }
373
Vladimir Homutov8e82f062014-05-26 23:34:44 +0400374 if (ngx_close_socket(peer->conn.fd) == -1) {
375 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
376 ngx_close_socket_n " failed");
Vladimir Homutov493b8982014-05-12 16:34:15 +0400377 }
378}