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