github.com/yankunsam/loki/v2@v2.6.3-0.20220817130409-389df5235c27/clients/pkg/promtail/targets/syslog/transport.go (about) 1 package syslog 2 3 import ( 4 "context" 5 "crypto/tls" 6 "crypto/x509" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "net" 11 "strings" 12 "sync" 13 "time" 14 15 "github.com/grafana/dskit/backoff" 16 "github.com/mwitkow/go-conntrack" 17 18 "github.com/go-kit/log" 19 "github.com/go-kit/log/level" 20 "github.com/grafana/loki/clients/pkg/promtail/scrapeconfig" 21 "github.com/grafana/loki/clients/pkg/promtail/targets/syslog/syslogparser" 22 "github.com/influxdata/go-syslog/v3" 23 "github.com/prometheus/prometheus/model/labels" 24 ) 25 26 var ( 27 protocolUDP = "udp" 28 protocolTCP = "tcp" 29 ) 30 31 type Transport interface { 32 Run() error 33 Addr() net.Addr 34 Ready() bool 35 Close() error 36 Wait() 37 } 38 39 type handleMessage func(labels.Labels, syslog.Message) 40 type handleMessageError func(error) 41 42 type baseTransport struct { 43 config *scrapeconfig.SyslogTargetConfig 44 logger log.Logger 45 46 openConnections *sync.WaitGroup 47 48 handleMessage handleMessage 49 handleMessageError handleMessageError 50 51 ctx context.Context 52 ctxCancel context.CancelFunc 53 } 54 55 func (t *baseTransport) close() { 56 t.ctxCancel() 57 } 58 59 // Ready implements SyslogTransport 60 func (t *baseTransport) Ready() bool { 61 return t.ctx.Err() == nil 62 } 63 64 func (t *baseTransport) idleTimeout() time.Duration { 65 if t.config.IdleTimeout != 0 { 66 return t.config.IdleTimeout 67 } 68 return defaultIdleTimeout 69 } 70 71 func (t *baseTransport) maxMessageLength() int { 72 if t.config.MaxMessageLength != 0 { 73 return t.config.MaxMessageLength 74 } 75 return defaultMaxMessageLength 76 } 77 78 func (t *baseTransport) connectionLabels(ip string) labels.Labels { 79 lb := labels.NewBuilder(nil) 80 for k, v := range t.config.Labels { 81 lb.Set(string(k), string(v)) 82 } 83 84 lb.Set("__syslog_connection_ip_address", ip) 85 lb.Set("__syslog_connection_hostname", lookupAddr(ip)) 86 87 return lb.Labels() 88 } 89 90 func ipFromConn(c net.Conn) net.IP { 91 switch addr := c.RemoteAddr().(type) { 92 case *net.TCPAddr: 93 return addr.IP 94 } 95 96 return nil 97 } 98 99 func lookupAddr(addr string) string { 100 names, _ := net.LookupAddr(addr) 101 return strings.Join(names, ",") 102 } 103 104 func newBaseTransport(config *scrapeconfig.SyslogTargetConfig, handleMessage handleMessage, handleError handleMessageError, logger log.Logger) *baseTransport { 105 ctx, cancel := context.WithCancel(context.Background()) 106 return &baseTransport{ 107 config: config, 108 logger: logger, 109 openConnections: new(sync.WaitGroup), 110 handleMessage: handleMessage, 111 handleMessageError: handleError, 112 ctx: ctx, 113 ctxCancel: cancel, 114 } 115 } 116 117 type idleTimeoutConn struct { 118 net.Conn 119 idleTimeout time.Duration 120 } 121 122 func (c *idleTimeoutConn) Write(p []byte) (int, error) { 123 c.setDeadline() 124 return c.Conn.Write(p) 125 } 126 127 func (c *idleTimeoutConn) Read(b []byte) (int, error) { 128 c.setDeadline() 129 return c.Conn.Read(b) 130 } 131 132 func (c *idleTimeoutConn) setDeadline() { 133 _ = c.Conn.SetDeadline(time.Now().Add(c.idleTimeout)) 134 } 135 136 type ConnPipe struct { 137 addr net.Addr 138 *io.PipeReader 139 *io.PipeWriter 140 } 141 142 func NewConnPipe(addr net.Addr) *ConnPipe { 143 pr, pw := io.Pipe() 144 return &ConnPipe{ 145 addr: addr, 146 PipeReader: pr, 147 PipeWriter: pw, 148 } 149 } 150 151 func (pipe *ConnPipe) Close() error { 152 if err := pipe.PipeWriter.Close(); err != nil { 153 return err 154 } 155 return nil 156 } 157 158 type TCPTransport struct { 159 *baseTransport 160 listener net.Listener 161 } 162 163 func NewSyslogTCPTransport(config *scrapeconfig.SyslogTargetConfig, handleMessage handleMessage, handleError handleMessageError, logger log.Logger) Transport { 164 return &TCPTransport{ 165 baseTransport: newBaseTransport(config, handleMessage, handleError, logger), 166 } 167 } 168 169 // Run implements SyslogTransport 170 func (t *TCPTransport) Run() error { 171 l, err := net.Listen(protocolTCP, t.config.ListenAddress) 172 l = conntrack.NewListener(l, conntrack.TrackWithName("syslog_target/"+t.config.ListenAddress)) 173 if err != nil { 174 return fmt.Errorf("error setting up syslog target: %w", err) 175 } 176 177 tlsEnabled := t.config.TLSConfig.CertFile != "" || t.config.TLSConfig.KeyFile != "" || t.config.TLSConfig.CAFile != "" 178 if tlsEnabled { 179 tlsConfig, err := newTLSConfig(t.config.TLSConfig.CertFile, t.config.TLSConfig.KeyFile, t.config.TLSConfig.CAFile) 180 if err != nil { 181 return fmt.Errorf("error setting up syslog target: %w", err) 182 } 183 l = tls.NewListener(l, tlsConfig) 184 } 185 186 t.listener = l 187 level.Info(t.logger).Log("msg", "syslog listening on address", "address", t.Addr().String(), "protocol", protocolTCP, "tls", tlsEnabled) 188 189 t.openConnections.Add(1) 190 go t.acceptConnections() 191 192 return nil 193 } 194 195 func newTLSConfig(certFile string, keyFile string, caFile string) (*tls.Config, error) { 196 if certFile == "" || keyFile == "" { 197 return nil, fmt.Errorf("certificate and key files are required") 198 } 199 200 certs, err := tls.LoadX509KeyPair(certFile, keyFile) 201 if err != nil { 202 return nil, fmt.Errorf("unable to load server certificate or key: %w", err) 203 } 204 205 tlsConfig := &tls.Config{ 206 Certificates: []tls.Certificate{certs}, 207 } 208 209 if caFile != "" { 210 caCert, err := ioutil.ReadFile(caFile) 211 if err != nil { 212 return nil, fmt.Errorf("unable to load client CA certificate: %w", err) 213 } 214 215 caCertPool := x509.NewCertPool() 216 if ok := caCertPool.AppendCertsFromPEM(caCert); !ok { 217 return nil, fmt.Errorf("unable to parse client CA certificate") 218 } 219 220 tlsConfig.ClientCAs = caCertPool 221 tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert 222 } 223 224 return tlsConfig, nil 225 } 226 227 func (t *TCPTransport) acceptConnections() { 228 defer t.openConnections.Done() 229 230 l := log.With(t.logger, "address", t.listener.Addr().String()) 231 232 backoff := backoff.New(t.ctx, backoff.Config{ 233 MinBackoff: 5 * time.Millisecond, 234 MaxBackoff: 1 * time.Second, 235 }) 236 237 for { 238 c, err := t.listener.Accept() 239 if err != nil { 240 if !t.Ready() { 241 level.Info(l).Log("msg", "syslog server shutting down", "protocol", protocolTCP, "err", t.ctx.Err()) 242 return 243 } 244 245 if ne, ok := err.(net.Error); ok && ne.Temporary() { 246 level.Warn(l).Log("msg", "failed to accept syslog connection", "err", err, "num_retries", backoff.NumRetries()) 247 backoff.Wait() 248 continue 249 } 250 251 level.Error(l).Log("msg", "failed to accept syslog connection. quiting", "err", err) 252 return 253 } 254 backoff.Reset() 255 256 t.openConnections.Add(1) 257 go t.handleConnection(c) 258 } 259 260 } 261 262 func (t *TCPTransport) handleConnection(cn net.Conn) { 263 defer t.openConnections.Done() 264 265 c := &idleTimeoutConn{cn, t.idleTimeout()} 266 267 handlerCtx, cancel := context.WithCancel(t.ctx) 268 defer cancel() 269 go func() { 270 <-handlerCtx.Done() 271 _ = c.Close() 272 }() 273 274 lbs := t.connectionLabels(ipFromConn(c).String()) 275 276 err := syslogparser.ParseStream(c, func(result *syslog.Result) { 277 if err := result.Error; err != nil { 278 t.handleMessageError(err) 279 return 280 } 281 t.handleMessage(lbs.Copy(), result.Message) 282 }, t.maxMessageLength()) 283 284 if err != nil { 285 level.Warn(t.logger).Log("msg", "error initializing syslog stream", "err", err) 286 } 287 } 288 289 // Close implements SyslogTransport 290 func (t *TCPTransport) Close() error { 291 t.baseTransport.close() 292 return t.listener.Close() 293 } 294 295 // Wait implements SyslogTransport 296 func (t *TCPTransport) Wait() { 297 t.openConnections.Wait() 298 } 299 300 // Addr implements SyslogTransport 301 func (t *TCPTransport) Addr() net.Addr { 302 return t.listener.Addr() 303 } 304 305 type UDPTransport struct { 306 *baseTransport 307 udpConn *net.UDPConn 308 } 309 310 func NewSyslogUDPTransport(config *scrapeconfig.SyslogTargetConfig, handleMessage handleMessage, handleError handleMessageError, logger log.Logger) Transport { 311 return &UDPTransport{ 312 baseTransport: newBaseTransport(config, handleMessage, handleError, logger), 313 } 314 } 315 316 // Run implements SyslogTransport 317 func (t *UDPTransport) Run() error { 318 var err error 319 addr, err := net.ResolveUDPAddr(protocolUDP, t.config.ListenAddress) 320 if err != nil { 321 return fmt.Errorf("error resolving UDP address: %w", err) 322 } 323 t.udpConn, err = net.ListenUDP(protocolUDP, addr) 324 if err != nil { 325 return fmt.Errorf("error setting up syslog target: %w", err) 326 } 327 _ = t.udpConn.SetReadBuffer(1024 * 1024) 328 level.Info(t.logger).Log("msg", "syslog listening on address", "address", t.Addr().String(), "protocol", protocolUDP) 329 330 t.openConnections.Add(1) 331 go t.acceptPackets() 332 return nil 333 } 334 335 // Close implements SyslogTransport 336 func (t *UDPTransport) Close() error { 337 t.baseTransport.close() 338 return t.udpConn.Close() 339 } 340 341 func (t *UDPTransport) acceptPackets() { 342 defer t.openConnections.Done() 343 344 var ( 345 n int 346 addr net.Addr 347 err error 348 ) 349 streams := make(map[string]*ConnPipe) 350 buf := make([]byte, t.maxMessageLength()) 351 352 for { 353 if !t.Ready() { 354 level.Info(t.logger).Log("msg", "syslog server shutting down", "protocol", protocolUDP, "err", t.ctx.Err()) 355 for _, stream := range streams { 356 if err = stream.Close(); err != nil { 357 level.Error(t.logger).Log("msg", "failed to close pipe", "err", err) 358 } 359 } 360 return 361 } 362 n, addr, err = t.udpConn.ReadFrom(buf) 363 if n <= 0 && err != nil { 364 level.Warn(t.logger).Log("msg", "failed to read packets", "addr", addr, "err", err) 365 continue 366 } 367 368 stream, ok := streams[addr.String()] 369 if !ok { 370 stream = NewConnPipe(addr) 371 streams[addr.String()] = stream 372 t.openConnections.Add(1) 373 go t.handleRcv(stream) 374 } 375 if _, err := stream.Write(buf[:n]); err != nil { 376 level.Warn(t.logger).Log("msg", "failed to write to stream", "addr", addr, "err", err) 377 } 378 } 379 } 380 381 func (t *UDPTransport) handleRcv(c *ConnPipe) { 382 defer t.openConnections.Done() 383 384 lbs := t.connectionLabels(c.addr.String()) 385 err := syslogparser.ParseStream(c, func(result *syslog.Result) { 386 if err := result.Error; err != nil { 387 t.handleMessageError(err) 388 } else { 389 t.handleMessage(lbs.Copy(), result.Message) 390 } 391 }, t.maxMessageLength()) 392 393 if err != nil { 394 level.Warn(t.logger).Log("msg", "error parsing syslog stream", "err", err) 395 } 396 } 397 398 // Wait implements SyslogTransport 399 func (t *UDPTransport) Wait() { 400 t.openConnections.Wait() 401 } 402 403 // Addr implements SyslogTransport 404 func (t *UDPTransport) Addr() net.Addr { 405 return t.udpConn.LocalAddr() 406 }