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	"net"
24	"strings"
25
26	"zabbix.com/internal/agent"
27)
28
29// AllowedPeers is preparsed content of field Server
30type AllowedPeers struct {
31	ips   []net.IP
32	nets  []*net.IPNet
33	names []string
34}
35
36// GetAllowedPeers is parses the Server field
37func GetAllowedPeers(options *agent.AgentOptions) (allowedPeers *AllowedPeers, err error) {
38	ap := &AllowedPeers{}
39
40	if options.Server != "" {
41		opts := strings.Split(options.Server, ",")
42		for _, o := range opts {
43			peer := strings.Trim(o, " \t")
44			if _, peerNet, err := net.ParseCIDR(peer); nil == err {
45				if ap.isPresent(peerNet) {
46					continue
47				}
48				ap.nets = append(ap.nets, peerNet)
49				maskLeadSize, maskTotalOnes := peerNet.Mask.Size()
50				if 0 == maskLeadSize && 128 == maskTotalOnes {
51					_, peerNet, _ = net.ParseCIDR("0.0.0.0/0")
52					if !ap.isPresent(peerNet) {
53						ap.nets = append(ap.nets, peerNet)
54					}
55				}
56			} else if peerip := net.ParseIP(peer); nil != peerip {
57				if ap.isPresent(peerip) {
58					continue
59				}
60				ap.ips = append(ap.ips, peerip)
61			} else if !ap.isPresent(peer) {
62				ap.names = append(ap.names, peer)
63			}
64		}
65	}
66
67	return ap, nil
68}
69
70// CheckPeer validate incoming connection peer
71func (ap *AllowedPeers) CheckPeer(ip net.IP) bool {
72	if ap.checkNetIP(ip) {
73		return true
74	}
75
76	for _, nameAllowed := range ap.names {
77		if ips, err := net.LookupHost(nameAllowed); nil == err {
78			for _, ipPeer := range ips {
79				ipAllowed := net.ParseIP(ipPeer)
80				if ipAllowed.Equal(ip) {
81					return true
82				}
83			}
84		}
85	}
86
87	return false
88}
89
90func (ap *AllowedPeers) isPresent(value interface{}) bool {
91	switch v := value.(type) {
92	case *net.IPNet:
93		for _, va := range ap.nets {
94			maskLeadSize, _ := va.Mask.Size()
95			maskLeadSizeNew, _ := v.Mask.Size()
96			if maskLeadSize <= maskLeadSizeNew && va.Contains(v.IP) {
97				return true
98			}
99		}
100	case net.IP:
101		if ap.checkNetIP(v) {
102			return true
103		}
104	case string:
105		for _, v := range ap.names {
106			if v == value {
107				return true
108			}
109		}
110	}
111
112	return false
113}
114
115func (ap *AllowedPeers) checkNetIP(ip net.IP) bool {
116	for _, netAllowed := range ap.nets {
117		if netAllowed.Contains(ip) {
118			return true
119		}
120	}
121	for _, ipAllowed := range ap.ips {
122		if ipAllowed.Equal(ip) {
123			return true
124		}
125	}
126	return false
127}
128