src/core/ngx_syslog.c - nginx-1.7.10

Global variables defined

Functions defined

Macros defined

Source code


  1. /*
  2. * Copyright (C) Nginx, Inc.
  3. */


  4. #include <ngx_config.h>
  5. #include <ngx_core.h>
  6. #include <ngx_event.h>


  7. #define NGX_SYSLOG_MAX_STR                                                    \
  8.      NGX_MAX_ERROR_STR + sizeof("<255>Jan 01 00:00:00 ") - 1                  \
  9.      + (NGX_MAXHOSTNAMELEN - 1) + 1 /* space */                               \
  10.      + 32 /* tag */ + 2 /* colon, space */


  11. static char *ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer);
  12. static ngx_int_t ngx_syslog_init_peer(ngx_syslog_peer_t *peer);
  13. static void ngx_syslog_cleanup(void *data);


  14. static char  *facilities[] = {
  15.     "kern", "user", "mail", "daemon", "auth", "intern", "lpr", "news", "uucp",
  16.     "clock", "authpriv", "ftp", "ntp", "audit", "alert", "cron", "local0",
  17.     "local1", "local2", "local3", "local4", "local5", "local6", "local7",
  18.     NULL
  19. };

  20. /* note 'error/warn' like in nginx.conf, not 'err/warning' */
  21. static char  *severities[] = {
  22.     "emerg", "alert", "crit", "error", "warn", "notice", "info", "debug", NULL
  23. };

  24. static ngx_log_t    ngx_syslog_dummy_log;
  25. static ngx_event_t  ngx_syslog_dummy_event;


  26. char *
  27. ngx_syslog_process_conf(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
  28. {
  29.     peer->pool = cf->pool;
  30.     peer->facility = NGX_CONF_UNSET_UINT;
  31.     peer->severity = NGX_CONF_UNSET_UINT;

  32.     if (ngx_syslog_parse_args(cf, peer) != NGX_CONF_OK) {
  33.         return NGX_CONF_ERROR;
  34.     }

  35.     if (peer->server.sockaddr == NULL) {
  36.         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  37.                            "no syslog server specified");
  38.         return NGX_CONF_ERROR;
  39.     }

  40.     if (peer->facility == NGX_CONF_UNSET_UINT) {
  41.         peer->facility = 23; /* local7 */
  42.     }

  43.     if (peer->severity == NGX_CONF_UNSET_UINT) {
  44.         peer->severity = 6; /* info */
  45.     }

  46.     if (peer->tag.data == NULL) {
  47.         ngx_str_set(&peer->tag, "nginx");
  48.     }

  49.     peer->conn.fd = (ngx_socket_t) -1;

  50.     return NGX_CONF_OK;
  51. }


  52. static char *
  53. ngx_syslog_parse_args(ngx_conf_t *cf, ngx_syslog_peer_t *peer)
  54. {
  55.     u_char      *p, *comma, c;
  56.     size_t       len;
  57.     ngx_str_t   *value;
  58.     ngx_url_t    u;
  59.     ngx_uint_t   i;

  60.     value = cf->args->elts;

  61.     p = value[1].data + sizeof("syslog:") - 1;

  62.     for ( ;; ) {
  63.         comma = (u_char *) ngx_strchr(p, ',');

  64.         if (comma != NULL) {
  65.             len = comma - p;
  66.             *comma = '\0';

  67.         } else {
  68.             len = value[1].data + value[1].len - p;
  69.         }

  70.         if (ngx_strncmp(p, "server=", 7) == 0) {

  71.             if (peer->server.sockaddr != NULL) {
  72.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  73.                                    "duplicate syslog \"server\"");
  74.                 return NGX_CONF_ERROR;
  75.             }

  76.             ngx_memzero(&u, sizeof(ngx_url_t));

  77.             u.url.data = p + 7;
  78.             u.url.len = len - 7;
  79.             u.default_port = 514;

  80.             if (ngx_parse_url(cf->pool, &u) != NGX_OK) {
  81.                 if (u.err) {
  82.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  83.                                        "%s in syslog server \"%V\"",
  84.                                        u.err, &u.url);
  85.                 }

  86.                 return NGX_CONF_ERROR;
  87.             }

  88.             peer->server = u.addrs[0];

  89.         } else if (ngx_strncmp(p, "facility=", 9) == 0) {

  90.             if (peer->facility != NGX_CONF_UNSET_UINT) {
  91.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  92.                                    "duplicate syslog \"facility\"");
  93.                 return NGX_CONF_ERROR;
  94.             }

  95.             for (i = 0; facilities[i] != NULL; i++) {

  96.                 if (ngx_strcmp(p + 9, facilities[i]) == 0) {
  97.                     peer->facility = i;
  98.                     goto next;
  99.                 }
  100.             }

  101.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  102.                                "unknown syslog facility \"%s\"", p + 9);
  103.             return NGX_CONF_ERROR;

  104.         } else if (ngx_strncmp(p, "severity=", 9) == 0) {

  105.             if (peer->severity != NGX_CONF_UNSET_UINT) {
  106.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  107.                                    "duplicate syslog \"severity\"");
  108.                 return NGX_CONF_ERROR;
  109.             }

  110.             for (i = 0; severities[i] != NULL; i++) {

  111.                 if (ngx_strcmp(p + 9, severities[i]) == 0) {
  112.                     peer->severity = i;
  113.                     goto next;
  114.                 }
  115.             }

  116.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  117.                                "unknown syslog severity \"%s\"", p + 9);
  118.             return NGX_CONF_ERROR;

  119.         } else if (ngx_strncmp(p, "tag=", 4) == 0) {

  120.             if (peer->tag.data != NULL) {
  121.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  122.                                    "duplicate syslog \"tag\"");
  123.                 return NGX_CONF_ERROR;
  124.             }

  125.             /*
  126.              * RFC 3164: the TAG is a string of ABNF alphanumeric characters
  127.              * that MUST NOT exceed 32 characters.
  128.              */
  129.             if (len - 4 > 32) {
  130.                 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  131.                                    "syslog tag length exceeds 32");
  132.                 return NGX_CONF_ERROR;
  133.             }

  134.             for (i = 4; i < len; i++) {
  135.                 c = ngx_tolower(p[i]);

  136.                 if (c < '0' || (c > '9' && c < 'a' && c != '_') || c > 'z') {
  137.                     ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  138.                                        "syslog \"tag\" only allows "
  139.                                        "alphanumeric characters "
  140.                                        "and underscore");
  141.                     return NGX_CONF_ERROR;
  142.                 }
  143.             }

  144.             peer->tag.data = p + 4;
  145.             peer->tag.len = len - 4;

  146.         } else {
  147.             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
  148.                                "unknown syslog parameter \"%s\"", p);
  149.             return NGX_CONF_ERROR;
  150.         }

  151.     next:

  152.         if (comma == NULL) {
  153.             break;
  154.         }

  155.         p = comma + 1;
  156.     }

  157.     return NGX_CONF_OK;
  158. }


  159. u_char *
  160. ngx_syslog_add_header(ngx_syslog_peer_t *peer, u_char *buf)
  161. {
  162.     ngx_uint_t  pri;

  163.     pri = peer->facility * 8 + peer->severity;

  164.     return ngx_sprintf(buf, "<%ui>%V %V %V: ", pri, &ngx_cached_syslog_time,
  165.                        &ngx_cycle->hostname, &peer->tag);
  166. }


  167. void
  168. ngx_syslog_writer(ngx_log_t *log, ngx_uint_t level, u_char *buf,
  169.     size_t len)
  170. {
  171.     u_char             *p, msg[NGX_SYSLOG_MAX_STR];
  172.     ngx_uint_t          head_len;
  173.     ngx_syslog_peer_t  *peer;

  174.     peer = log->wdata;

  175.     if (peer->busy) {
  176.         return;
  177.     }

  178.     peer->busy = 1;
  179.     peer->severity = level - 1;

  180.     p = ngx_syslog_add_header(peer, msg);
  181.     head_len = p - msg;

  182.     len -= NGX_LINEFEED_SIZE;

  183.     if (len > NGX_SYSLOG_MAX_STR - head_len) {
  184.         len = NGX_SYSLOG_MAX_STR - head_len;
  185.     }

  186.     p = ngx_snprintf(p, len, "%s", buf);

  187.     (void) ngx_syslog_send(peer, msg, p - msg);

  188.     peer->busy = 0;
  189. }


  190. ssize_t
  191. ngx_syslog_send(ngx_syslog_peer_t *peer, u_char *buf, size_t len)
  192. {
  193.     ssize_t  n;

  194.     if (peer->conn.fd == (ngx_socket_t) -1) {
  195.         if (ngx_syslog_init_peer(peer) != NGX_OK) {
  196.             return NGX_ERROR;
  197.         }
  198.     }

  199.     /* log syslog socket events with valid log */
  200.     peer->conn.log = ngx_cycle->log;

  201.     if (ngx_send) {
  202.         n = ngx_send(&peer->conn, buf, len);

  203.     } else {
  204.         /* event module has not yet set ngx_io */
  205.         n = ngx_os_io.send(&peer->conn, buf, len);
  206.     }

  207. #if (NGX_HAVE_UNIX_DOMAIN)

  208.     if (n == NGX_ERROR && peer->server.sockaddr->sa_family == AF_UNIX) {

  209.         if (ngx_close_socket(peer->conn.fd) == -1) {
  210.             ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
  211.                           ngx_close_socket_n " failed");
  212.         }

  213.         peer->conn.fd = (ngx_socket_t) -1;
  214.     }

  215. #endif

  216.     return n;
  217. }


  218. static ngx_int_t
  219. ngx_syslog_init_peer(ngx_syslog_peer_t *peer)
  220. {
  221.     ngx_socket_t         fd;
  222.     ngx_pool_cleanup_t  *cln;

  223.     peer->conn.read = &ngx_syslog_dummy_event;
  224.     peer->conn.write = &ngx_syslog_dummy_event;

  225.     ngx_syslog_dummy_event.log = &ngx_syslog_dummy_log;

  226.     fd = ngx_socket(peer->server.sockaddr->sa_family, SOCK_DGRAM, 0);
  227.     if (fd == (ngx_socket_t) -1) {
  228.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
  229.                       ngx_socket_n " failed");
  230.         return NGX_ERROR;
  231.     }

  232.     if (ngx_nonblocking(fd) == -1) {
  233.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
  234.                       ngx_nonblocking_n " failed");
  235.         goto failed;
  236.     }

  237.     if (connect(fd, peer->server.sockaddr, peer->server.socklen) == -1) {
  238.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
  239.                       "connect() failed");
  240.         goto failed;
  241.     }

  242.     cln = ngx_pool_cleanup_add(peer->pool, 0);
  243.     if (cln == NULL) {
  244.         goto failed;
  245.     }

  246.     cln->data = peer;
  247.     cln->handler = ngx_syslog_cleanup;

  248.     peer->conn.fd = fd;

  249.     /* UDP sockets are always ready to write */
  250.     peer->conn.write->ready = 1;

  251.     return NGX_OK;

  252. failed:

  253.     if (ngx_close_socket(fd) == -1) {
  254.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
  255.                       ngx_close_socket_n " failed");
  256.     }

  257.     return NGX_ERROR;
  258. }


  259. static void
  260. ngx_syslog_cleanup(void *data)
  261. {
  262.     ngx_syslog_peer_t  *peer = data;

  263.     /* prevents further use of this peer */
  264.     peer->busy = 1;

  265.     if (peer->conn.fd == (ngx_socket_t) -1) {
  266.         return;
  267.     }

  268.     if (ngx_close_socket(peer->conn.fd) == -1) {
  269.         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_socket_errno,
  270.                       ngx_close_socket_n " failed");
  271.     }
  272. }