1c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 2c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Copyright (C) 2013 The Android Open Source Project 3c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 4c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Licensed under the Apache License, Version 2.0 (the "License"); 5c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// you may not use this file except in compliance with the License. 6c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// You may obtain a copy of the License at 7c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 8c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// http://www.apache.org/licenses/LICENSE-2.0 9c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 10c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// Unless required by applicable law or agreed to in writing, software 11c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// distributed under the License is distributed on an "AS IS" BASIS, 12c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// See the License for the specific language governing permissions and 14c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// limitations under the License. 15c0beca55d290fe0b1c96d78cbbcf94b05c23f5a5Peter Qiu// 161c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 171c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// netfilter_queue_helper is a user-space process that allows unicast 181c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// replies to multicast requests. It does so by monitoring output 191c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// multicast packets on one NFQUEUE netlink iptables rule and collating 201c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// a list of input ports that are sending out multicast requests. It 211c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// uses these results to set policy on incoming UDP packets on a separate 221c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// NFQUEUE for replies addressed to that list of ports. 231c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// 241c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// Expected usage: 251c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// iptables -I OUTPUT 1 --proto udp 261c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// --destination <destination_multicast_address> --dport <dport> 271c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// -j NFQUEUE --queue-num <output_queue_number> 281c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// iptables -A INPUT --proto udp -j NFQUEUE --queue-num <input_queue_number> 291c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// netfilter_queue_helper --input-queue=<input_queue_number> 301c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// --output-queue=<output_queue_number> 311c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// 321c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// Note: in the above example, we preprend the OUTPUT rule so that it 331c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// runs even if lower rules would have accepted it, while the INPUT 341c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// rule is placed at the end of the rule list so any other firewall 351c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// rules that would have accepted the input packet for other reasons 361c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// will be evaluated first so we don't have to involve userspace for them. 371c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 381c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 391c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart#include <string> 401c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 411c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart#include <base/command_line.h> 421c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart#include <base/logging.h> 43a0ddf46e466bd4ba3d20952f0a6988c680c1af14Ben Chan#include <base/strings/string_number_conversions.h> 4403e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko#include <brillo/syslog_logging.h> 451c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 461c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart#include "shill/shims/netfilter_queue_processor.h" 471c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 481c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewartusing std::string; 491c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 501c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewartnamespace switches { 511c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 521c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewartstatic const char kHelp[] = "help"; 531c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewartstatic const char kInputQueue[] = "input-queue"; 541c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewartstatic const char kOutputQueue[] = "output-queue"; 553fe66041142135b0f40820bee17376a77bf3bec1Paul Stewartstatic const char kVerbose[] = "verbose"; 561c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 571c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart// The help message shown if help flag is passed to the program. 581c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewartstatic const char kHelpMessage[] = "\n" 591c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart "Available Switches:\n" 601c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart " --help\n" 611c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart " Show this help message.\n" 621c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart " --input-queue=<input queue number>\n" 631c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart " Set the netfilter queue number for incoming UDP packets.\n" 641c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart " --output-queue=<output queue number>\n" 651c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart " Set the netfilter queue number for outgoing UDP packets for which\n" 663fe66041142135b0f40820bee17376a77bf3bec1Paul Stewart " input replies will be enabled.\n" 673fe66041142135b0f40820bee17376a77bf3bec1Paul Stewart " --verbose\n" 683fe66041142135b0f40820bee17376a77bf3bec1Paul Stewart " Show debug messages.\n"; 691c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 701c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart} // namespace switches 711c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 72758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewartbool GetIntegerOption(base::CommandLine* cl, const string& option, int* value) { 731c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart if (!cl->HasSwitch(option)) { 741c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart LOG(ERROR) << "Option " << option << " was not given."; 751c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart return false; 761c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart } 771c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart string option_string_value = cl->GetSwitchValueASCII(option); 781c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart int option_integer_value = -1; 791c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 801c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart if (!base::StringToInt(option_string_value, &option_integer_value)) { 811c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart LOG(ERROR) << "Unable to convert parameter \"" 821c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart << option_string_value 831c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart << "\" passed as option " 841c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart << option 851c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart << " into an integer."; 861c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart return false; 871c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart } 881c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart *value = option_integer_value; 891c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart return true; 901c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart} 911c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 92758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewartint main(int argc, char** argv) { 93127f2565a985650963d6109fc3a32c3da6a17d32Alex Vakulenko base::CommandLine::Init(argc, argv); 94758dee3579a092825bf481a7610b4c7c4df99b8ePaul Stewart base::CommandLine* cl = base::CommandLine::ForCurrentProcess(); 951c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 961c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart if (cl->HasSwitch(switches::kHelp)) { 971c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart LOG(INFO) << switches::kHelpMessage; 981c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart return 0; 991c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart } 1001c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 1011c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart int input_queue = -1; 1021c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart if (!GetIntegerOption(cl, switches::kInputQueue, &input_queue) || 1031c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart input_queue < 0) { 1041c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart LOG(ERROR) << "Unable to get mandatory input queue option."; 1051c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart return 1; 1061c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart } 1071c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 1081c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart int output_queue = -1; 1091c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart if (!GetIntegerOption(cl, switches::kOutputQueue, &output_queue) || 1101c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart output_queue < 0) { 1111c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart LOG(ERROR) << "Unable to get mandatory output queue option."; 1121c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart return 1; 1131c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart } 1141c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 1153fe66041142135b0f40820bee17376a77bf3bec1Paul Stewart if (cl->HasSwitch(switches::kVerbose)) { 1163fe66041142135b0f40820bee17376a77bf3bec1Paul Stewart logging::SetMinLogLevel(-3); 1173fe66041142135b0f40820bee17376a77bf3bec1Paul Stewart } 1183fe66041142135b0f40820bee17376a77bf3bec1Paul Stewart 1191c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart if (output_queue == input_queue) { 1201c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart LOG(ERROR) << "Input and output queues must not be the same."; 1211c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart return 1; 1221c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart } 1231c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 12403e6719bae1e0903d94853b896673a033196bcf5Alex Vakulenko brillo::InitLog(brillo::kLogToSyslog | brillo::kLogHeader); 1251c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 1261c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart shill::shims::NetfilterQueueProcessor processor(input_queue, output_queue); 1271c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 1281c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart if (!processor.Start()) { 1291c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart LOG(ERROR) << "Failed to start netfilter processor."; 1301c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart return 1; 1311c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart } 1321c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 1331c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart processor.Run(); 1341c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart 1351c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart return 0; 1361c9a566b9b128096b77c537bedfbbfd9e9d1b72ePaul Stewart} 137