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