Bug 252095

Summary: logger not sending hostname or timestamp to loghost when using capsicum
Product: Base System Reporter: Gunther Schadow <raj>
Component: binAssignee: freebsd-bugs (Nobody) <bugs>
Status: New ---    
Severity: Affects Some People CC: bdrewery, oshogbo
Priority: ---    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description Gunther Schadow 2020-12-24 03:09:24 UTC
When remote logging, the syslogd does not send the hostname over to the loghost. 

Example, in syslog client's syslog.conf

    *.*  /var/log/all.log
    *.*  @loghost

syslog server is started with 

    syslogd -a 0.0.0.0/0 -H 

(network can be constraint, doesn't matter). The /etc/hosts nor DNS may have all the hosts registered, it is not important or even desirable that the syslog server translates the IP address to a hostname, hence the -H flag.

Now, when I do 

    logger -h loghost -H pb00 test

the loghost's syslogd receives the "pb00" hostname and logs it. 

When I do

    logger -h loghost test

then also the syslogd recieves the client's current hostname and logs it.

But when intermediating through the client's own syslogd

    logger test

then the client's syslogd will not send its hostname over to the loghost, and then the loghost will attempt to decode the hostname via DNS or /etc/hosts. I think the syslogd should send its hostname over to the client, or the hostname which it originally received. 

Interestingly, the above command will log the own hostname in the all.log log file on the syslogd client, which will forward to the loghost without informing its own idea of its hostname.

    logger -H xx00 test

interestingly, that also does not log the xx00 name on the local syslogd in all.log even if I started the local syslogd with the -H flag.

I consider this behavior a bug in that there is no reason why the syslogd should withhold its own idea of its hostname or the original hostname provided in the log message on to the remote logger. 

I browsed through the source code and couldn't immediately find how I could quickly fix this, but it seems the issue is somewhere here around line 1790:

                lsent = 0;
                for (r = f->fu_forw_addr; r; r = r->ai_next) {
                        memset(&msghdr, 0, sizeof(msghdr));
                        msghdr.msg_name = r->ai_addr;
                        msghdr.msg_namelen = r->ai_addrlen;
                        msghdr.msg_iov = il->iov;
                        msghdr.msg_iovlen = il->iovcnt;
                        STAILQ_FOREACH(sl, &shead, next) {
                                if (sl->sl_ss.ss_family == AF_LOCAL ||
                                    sl->sl_ss.ss_family == AF_UNSPEC ||
                                    sl->sl_socket < 0)
                                        continue;
                                lsent = sendmsg(sl->sl_socket, &msghdr, 0);
                                if (lsent == (ssize_t)il->totalsize)
                                        break;
                        }
                        if (lsent == (ssize_t)il->totalsize && !send_to_all)
                                break;
                }

when I looked at the packets with tcpdump, it seemed that the forwarded packets had no hostname of any kind in it.
Comment 1 Bryan Drewery freebsd_committer freebsd_triage 2022-05-12 18:52:40 UTC
The problem is that logger((1) uses capsicum now which ends up forwarding the entire message to syslog(3) which then adds its own hostname. syslog(3) does not support passing a hostname.
If using logger -h then capsicum is disabled and the hostname is sent in a direct socket.


  static void                                                              
  logmessage(int pri, const char *timestamp, const char *hostname,         
      const char *tag, struct socks *sk, ssize_t nsock, const char *buf)   
  {                                                                        
          char *line;                                                      
          int len, i, lsent;                                               
  
  // nsock != 0 when -h is given                                                                         
          if (nsock == 0) {                                                
                  cap_syslog(capsyslog, pri, "%s", buf);                   
                  return;                                                  
          }                                                                
  // no capsicum, use custom format with hostname
          if ((len = asprintf(&line, "<%d>%s %s %s: %s", pri, timestamp,   
              hostname, tag, buf)) == -1)                                  
                  errx(1, "asprintf");                                     
                                                                           
          lsent = -1;                                                      
          for (i = 0; i < nsock; i++) {                                    
                  lsent = sendto(sk[i].sk_sock, line, len, 0,              
                                 sstosa(&sk[i].sk_addr), sk[i].sk_addrlen);
Comment 2 Bryan Drewery freebsd_committer freebsd_triage 2022-05-12 18:58:37 UTC
Actually tag is sent in cap_opensyslog. Unsure if timestamp obeys environment TZ via capsicum.
Comment 3 Bryan Drewery freebsd_committer freebsd_triage 2022-05-12 19:03:35 UTC
I think a possible fix would be to add an API for passing hostname to syslog(3). Naming is just an example:
  openlog2(const char *ident, int logopt, int facility, const char *hostname)
This could be kept set like the tag and facility already are.
Then capsicum's syslog API could learn of it as well.