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)
35
36type ServerListener struct {
37	listenerID   int
38	listener     *zbxcomms.Listener
39	scheduler    scheduler.Scheduler
40	options      *agent.AgentOptions
41	tlsConfig    *tls.Config
42	allowedPeers *AllowedPeers
43	bindIP       string
44}
45
46func (sl *ServerListener) processConnection(conn *zbxcomms.Connection) (err error) {
47	defer func() {
48		if err != nil {
49			conn.Close()
50		}
51	}()
52
53	var data []byte
54	if data, err = conn.Read(); err != nil {
55		return
56	}
57
58	log.Debugf("received passive check request: '%s' from '%s'", string(data), conn.RemoteIP())
59
60	response := passiveCheck{conn: &passiveConnection{conn: conn}, scheduler: sl.scheduler}
61	go response.handleCheck(data)
62
63	return nil
64}
65
66func (sl *ServerListener) run() {
67	defer log.PanicHook()
68	log.Debugf("[%d] starting listener for '%s:%d'", sl.listenerID, sl.bindIP, sl.options.ListenPort)
69
70	for {
71		conn, err := sl.listener.Accept(time.Second*time.Duration(sl.options.Timeout),
72			zbxcomms.TimeoutModeShift)
73
74		if err == nil {
75			if !sl.allowedPeers.CheckPeer(net.ParseIP(conn.RemoteIP())) {
76				conn.Close()
77				log.Warningf("cannot accept incoming connection for peer: %s", conn.RemoteIP())
78			} else if err := sl.processConnection(conn); err != nil {
79				log.Warningf("cannot process incoming connection: %s", err.Error())
80			}
81		} else {
82			if nerr, ok := err.(net.Error); ok && nerr.Temporary() {
83				log.Errf("cannot accept incoming connection: %s", err.Error())
84				continue
85			}
86			break
87		}
88	}
89
90	log.Debugf("listener has been stopped")
91	monitor.Unregister(monitor.Input)
92
93}
94
95func New(listenerID int, s scheduler.Scheduler, bindIP string, options *agent.AgentOptions) (sl *ServerListener) {
96	sl = &ServerListener{listenerID: listenerID, scheduler: s, bindIP: bindIP, options: options}
97	return
98}
99
100func (sl *ServerListener) Start() (err error) {
101	if sl.tlsConfig, err = agent.GetTLSConfig(sl.options); err != nil {
102		return
103	}
104	if sl.allowedPeers, err = GetAllowedPeers(sl.options); err != nil {
105		return
106	}
107	if sl.listener, err = zbxcomms.Listen(fmt.Sprintf("[%s]:%d", sl.bindIP, sl.options.ListenPort), sl.tlsConfig); err != nil {
108		return
109	}
110	monitor.Register(monitor.Input)
111	go sl.run()
112	return
113}
114
115func (sl *ServerListener) Stop() {
116	if sl.listener != nil {
117		sl.listener.Close()
118	}
119}
120
121// ParseListenIP validate ListenIP value
122func ParseListenIP(options *agent.AgentOptions) (ips []string, err error) {
123	if 0 == len(options.ListenIP) || options.ListenIP == "0.0.0.0" {
124		return []string{"0.0.0.0"}, nil
125	}
126	lips := getListLocalIP()
127	opts := strings.Split(options.ListenIP, ",")
128	for _, o := range opts {
129		addr := strings.Trim(o, " \t")
130		if err = validateLocalIP(addr, lips); nil != err {
131			return nil, err
132		}
133		ips = append(ips, addr)
134	}
135	return ips, nil
136}
137
138func validateLocalIP(addr string, lips *[]net.IP) (err error) {
139	if ip := net.ParseIP(addr); nil != ip {
140		if ip.IsLoopback() || 0 == len(*lips) {
141			return nil
142		}
143		for _, lip := range *lips {
144			if lip.Equal(ip) {
145				return nil
146			}
147		}
148	} else {
149		return fmt.Errorf("incorrect value of ListenIP: \"%s\"", addr)
150	}
151	return fmt.Errorf("value of ListenIP not present on the host: \"%s\"", addr)
152}
153
154func getListLocalIP() *[]net.IP {
155	var ips []net.IP
156
157	ifaces, err := net.Interfaces()
158	if nil != err {
159		return &ips
160	}
161
162	for _, i := range ifaces {
163		addrs, err := i.Addrs()
164		if nil != err {
165			return &ips
166		}
167
168		for _, addr := range addrs {
169			var ip net.IP
170			switch v := addr.(type) {
171			case *net.IPNet:
172				ip = v.IP
173			case *net.IPAddr:
174				ip = v.IP
175			}
176			ips = append(ips, ip)
177		}
178	}
179
180	return &ips
181}
182