1/*
2** Zabbix
3** Copyright (C) 2001-2021 Zabbix SIA
4**
5** This program is free software; you can redistribute it and/or modify
6** it under the terms of the GNU General Public License as published by
7** the Free Software Foundation; either version 2 of the License, or
8** (at your option) any later version.
9**
10** This program is distributed in the hope that it will be useful,
11** but WITHOUT ANY WARRANTY; without even the implied warranty of
12** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13** GNU General Public License for more details.
14**
15** You should have received a copy of the GNU General Public License
16** along with this program; if not, write to the Free Software
17** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
18**/
19
20package serverlistener
21
22import (
23	"fmt"
24	"net"
25	"strings"
26	"time"
27
28	"zabbix.com/internal/agent"
29	"zabbix.com/internal/agent/scheduler"
30	"zabbix.com/internal/monitor"
31	"zabbix.com/pkg/log"
32	"zabbix.com/pkg/tls"
33	"zabbix.com/pkg/zbxcomms"
34	"zabbix.com/pkg/zbxnet"
35)
36
37type ServerListener struct {
38	listenerID   int
39	listener     *zbxcomms.Listener
40	scheduler    scheduler.Scheduler
41	options      *agent.AgentOptions
42	tlsConfig    *tls.Config
43	allowedPeers *zbxnet.AllowedPeers
44	bindIP       string
45}
46
47func (sl *ServerListener) processConnection(conn *zbxcomms.Connection) (err error) {
48	defer func() {
49		if err != nil {
50			conn.Close()
51		}
52	}()
53
54	var data []byte
55	if data, err = conn.Read(); err != nil {
56		return
57	}
58
59	log.Debugf("received passive check request: '%s' from '%s'", string(data), conn.RemoteIP())
60
61	response := passiveCheck{conn: &passiveConnection{conn: conn}, scheduler: sl.scheduler}
62	go response.handleCheck(data)
63
64	return nil
65}
66
67func (sl *ServerListener) run() {
68	defer log.PanicHook()
69	log.Debugf("[%d] starting listener for '%s:%d'", sl.listenerID, sl.bindIP, sl.options.ListenPort)
70
71	for {
72		conn, err := sl.listener.Accept(time.Second*time.Duration(sl.options.Timeout),
73			zbxcomms.TimeoutModeShift)
74
75		if err == nil {
76			if !sl.allowedPeers.CheckPeer(net.ParseIP(conn.RemoteIP())) {
77				conn.Close()
78				log.Warningf("cannot accept incoming connection for peer: %s", conn.RemoteIP())
79			} else if err := sl.processConnection(conn); err != nil {
80				log.Warningf("cannot process incoming connection: %s", err.Error())
81			}
82		} else {
83			if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
84				log.Errf("cannot accept incoming connection: %s", err.Error())
85				continue
86			}
87			break
88		}
89	}
90
91	log.Debugf("listener has been stopped")
92	monitor.Unregister(monitor.Input)
93
94}
95
96func New(listenerID int, s scheduler.Scheduler, bindIP string, options *agent.AgentOptions) (sl *ServerListener) {
97	sl = &ServerListener{listenerID: listenerID, scheduler: s, bindIP: bindIP, options: options}
98	return
99}
100
101func (sl *ServerListener) Start() (err error) {
102	if sl.tlsConfig, err = agent.GetTLSConfig(sl.options); err != nil {
103		return
104	}
105	if sl.allowedPeers, err = zbxnet.GetAllowedPeers(sl.options.Server); err != nil {
106		return
107	}
108	if sl.listener, err = zbxcomms.Listen(fmt.Sprintf("[%s]:%d", sl.bindIP, sl.options.ListenPort), sl.tlsConfig); err != nil {
109		return
110	}
111	monitor.Register(monitor.Input)
112	go sl.run()
113	return
114}
115
116func (sl *ServerListener) Stop() {
117	if sl.listener != nil {
118		sl.listener.Close()
119	}
120}
121
122// ParseListenIP validate ListenIP value
123func ParseListenIP(options *agent.AgentOptions) (ips []string, err error) {
124	if 0 == len(options.ListenIP) || options.ListenIP == "0.0.0.0" {
125		return []string{"0.0.0.0"}, nil
126	}
127	lips := getListLocalIP()
128	opts := strings.Split(options.ListenIP, ",")
129	for _, o := range opts {
130		addr := strings.Trim(o, " \t")
131		if err = validateLocalIP(addr, lips); nil != err {
132			return nil, err
133		}
134		ips = append(ips, addr)
135	}
136	return ips, nil
137}
138
139func validateLocalIP(addr string, lips *[]net.IP) (err error) {
140	if ip := net.ParseIP(addr); nil != ip {
141		if ip.IsLoopback() || 0 == len(*lips) {
142			return nil
143		}
144		for _, lip := range *lips {
145			if lip.Equal(ip) {
146				return nil
147			}
148		}
149	} else {
150		return fmt.Errorf("incorrect value of ListenIP: \"%s\"", addr)
151	}
152	return fmt.Errorf("value of ListenIP not present on the host: \"%s\"", addr)
153}
154
155func getListLocalIP() *[]net.IP {
156	var ips []net.IP
157
158	ifaces, err := net.Interfaces()
159	if nil != err {
160		return &ips
161	}
162
163	for _, i := range ifaces {
164		addrs, err := i.Addrs()
165		if nil != err {
166			return &ips
167		}
168
169		for _, addr := range addrs {
170			var ip net.IP
171			switch v := addr.(type) {
172			case *net.IPNet:
173				ip = v.IP
174			case *net.IPAddr:
175				ip = v.IP
176			}
177			ips = append(ips, ip)
178		}
179	}
180
181	return &ips
182}
183