1package srslog
2
3import (
4	"crypto/tls"
5	"crypto/x509"
6	"errors"
7	"io/ioutil"
8	"log"
9	"net"
10	"os"
11)
12
13// This interface allows us to work with both local and network connections,
14// and enables Solaris support (see syslog_unix.go).
15type serverConn interface {
16	writeString(framer Framer, formatter Formatter, p Priority, hostname, tag, s string) error
17	close() error
18}
19
20// DialFunc is the function signature to be used for a custom dialer callback
21// with DialWithCustomDialer
22type DialFunc func(string, string) (net.Conn, error)
23
24// New establishes a new connection to the system log daemon.  Each
25// write to the returned Writer sends a log message with the given
26// priority and prefix.
27func New(priority Priority, tag string) (w *Writer, err error) {
28	return Dial("", "", priority, tag)
29}
30
31// Dial establishes a connection to a log daemon by connecting to
32// address raddr on the specified network.  Each write to the returned
33// Writer sends a log message with the given facility, severity and
34// tag.
35// If network is empty, Dial will connect to the local syslog server.
36func Dial(network, raddr string, priority Priority, tag string) (*Writer, error) {
37	return DialWithTLSConfig(network, raddr, priority, tag, nil)
38}
39
40// ErrNilDialFunc is returned from DialWithCustomDialer when a nil DialFunc is passed,
41// avoiding a nil pointer deference panic.
42var ErrNilDialFunc = errors.New("srslog: nil DialFunc passed to DialWithCustomDialer")
43
44// DialWithCustomDialer establishes a connection by calling customDial.
45// Each write to the returned Writer sends a log message with the given facility, severity and tag.
46// Network must be "custom" in order for this package to use customDial.
47// While network and raddr will be passed to customDial, it is allowed for customDial to ignore them.
48// If customDial is nil, this function returns ErrNilDialFunc.
49func DialWithCustomDialer(network, raddr string, priority Priority, tag string, customDial DialFunc) (*Writer, error) {
50	if customDial == nil {
51		return nil, ErrNilDialFunc
52	}
53	return dialAllParameters(network, raddr, priority, tag, nil, customDial)
54}
55
56// DialWithTLSCertPath establishes a secure connection to a log daemon by connecting to
57// address raddr on the specified network. It uses certPath to load TLS certificates and configure
58// the secure connection.
59func DialWithTLSCertPath(network, raddr string, priority Priority, tag, certPath string) (*Writer, error) {
60	serverCert, err := ioutil.ReadFile(certPath)
61	if err != nil {
62		return nil, err
63	}
64
65	return DialWithTLSCert(network, raddr, priority, tag, serverCert)
66}
67
68// DialWIthTLSCert establishes a secure connection to a log daemon by connecting to
69// address raddr on the specified network. It uses serverCert to load a TLS certificate
70// and configure the secure connection.
71func DialWithTLSCert(network, raddr string, priority Priority, tag string, serverCert []byte) (*Writer, error) {
72	pool := x509.NewCertPool()
73	pool.AppendCertsFromPEM(serverCert)
74	config := tls.Config{
75		RootCAs: pool,
76	}
77
78	return DialWithTLSConfig(network, raddr, priority, tag, &config)
79}
80
81// DialWithTLSConfig establishes a secure connection to a log daemon by connecting to
82// address raddr on the specified network. It uses tlsConfig to configure the secure connection.
83func DialWithTLSConfig(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config) (*Writer, error) {
84	return dialAllParameters(network, raddr, priority, tag, tlsConfig, nil)
85}
86
87// implementation of the various functions above
88func dialAllParameters(network, raddr string, priority Priority, tag string, tlsConfig *tls.Config, customDial DialFunc) (*Writer, error) {
89	if err := validatePriority(priority); err != nil {
90		return nil, err
91	}
92
93	if tag == "" {
94		tag = os.Args[0]
95	}
96	hostname, _ := os.Hostname()
97
98	w := &Writer{
99		priority:   priority,
100		tag:        tag,
101		hostname:   hostname,
102		network:    network,
103		raddr:      raddr,
104		tlsConfig:  tlsConfig,
105		customDial: customDial,
106	}
107
108	_, err := w.connect()
109	if err != nil {
110		return nil, err
111	}
112	return w, err
113}
114
115// NewLogger creates a log.Logger whose output is written to
116// the system log service with the specified priority. The logFlag
117// argument is the flag set passed through to log.New to create
118// the Logger.
119func NewLogger(p Priority, logFlag int) (*log.Logger, error) {
120	s, err := New(p, "")
121	if err != nil {
122		return nil, err
123	}
124	return log.New(s, "", logFlag), nil
125}
126