1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation.  You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // config_ignore_ports.cc author Josh Rosenbaum <jrosenba@cisco.com>
19 
20 #include <sstream>
21 #include <vector>
22 #include <string>
23 #include <stdexcept>
24 
25 #include "conversion_state.h"
26 #include "helpers/converter.h"
27 #include "helpers/s2l_util.h"
28 #include "helpers/util_binder.h"
29 
30 namespace config
31 {
32 namespace
33 {
34 constexpr uint16_t MAX_PORTS = 0xFFFF; // == 65535
35 
36 class IgnorePorts : public ConversionState
37 {
38 public:
IgnorePorts(Converter & c)39     IgnorePorts(Converter& c) : ConversionState(c) { }
40     bool convert(std::istringstream& data_stream) override;
41 };
42 } // namespace
43 
convert(std::istringstream & data_stream)44 bool IgnorePorts::convert(std::istringstream& data_stream)
45 {
46     bool retval = true;
47     std::string keyword;
48     std::string port;
49 
50     std::streamoff pos = data_stream.tellg();
51     std::string port_string = data_stream.str();
52     port_string = port_string.substr(pos);
53     port_string = data_api.expand_vars(port_string);
54 
55     // if the keyword is not 'tcp' or 'udp', return false;
56     if (!(data_stream >> keyword) ||
57         (keyword != "udp" && keyword != "tcp") )
58     {
59         data_api.failed_conversion(data_stream, keyword);
60         return false;
61     }
62 
63     // Only add to the binder once we have validated the configuration.
64     auto& bind = cv.make_binder();
65     bind.set_when_proto(keyword);
66 
67     while (data_stream >> port)
68     {
69         try
70         {
71             const std::size_t colon_pos = port.find(':');
72 
73             if (port == "any")
74             {
75                 // Possible Snort bug, but only port zero is ignored
76                 bind.add_when_port("0");
77             }
78             else if (colon_pos == std::string::npos)
79             {
80                 bind.add_when_port(port);
81             }
82             else if (colon_pos == 0)
83             {
84                 int high = std::stoi(port.substr(1));
85 
86                 if (high > MAX_PORTS)
87                     throw std::out_of_range("");
88 
89                 for (int i = 0; i <= high; i++)
90                     bind.add_when_port(std::to_string(i));
91             }
92             else if ((colon_pos+1)  == port.size())
93             {
94                 int low = std::stoi(port.substr(0, colon_pos));
95 
96                 if (low > MAX_PORTS)
97                     throw std::out_of_range("");
98 
99                 for (int i = low; i <= MAX_PORTS; i++)
100                     bind.add_when_port(std::to_string(i));
101             }
102             else
103             {
104                 int low = std::stoi(port.substr(0, colon_pos));
105                 int high = std::stoi(port.substr(colon_pos + 1));
106 
107                 if (low > MAX_PORTS || high > MAX_PORTS || low > high)
108                     throw std::out_of_range("");
109 
110                 for (int i = low; i <= high; i++)
111                     bind.add_when_port(std::to_string(i));
112             }
113         }
114         catch (std::invalid_argument&)
115         {
116             data_api.failed_conversion(data_stream, "can't convert " + port);
117             retval = false;
118             bind.print_binding(false); // don't print the binding if an error occurred
119         }
120         catch (std::out_of_range&)
121         {
122             data_api.failed_conversion(data_stream, "Port" + port + " must be <= 65535");
123             retval = false;
124             bind.print_binding(false); // don't print the binding if an error occurred
125         }
126     }
127 
128     bind.set_use_action("allow");
129     return retval;
130 }
131 
132 /**************************
133  *******  A P I ***********
134  **************************/
135 
ctor(Converter & c)136 static ConversionState* ctor(Converter& c)
137 { return new IgnorePorts(c); }
138 
139 static const ConvertMap config_ignore_ports =
140 {
141     "ignore_ports",
142     ctor,
143 };
144 
145 const ConvertMap* ignore_ports_map = &config_ignore_ports;
146 } // namespace config
147 
148