134a5582cSAlexander V. Chernikov#!/usr/bin/env python 234a5582cSAlexander V. Chernikov# - 334a5582cSAlexander V. Chernikov# SPDX-License-Identifier: BSD-2-Clause 434a5582cSAlexander V. Chernikov# 534a5582cSAlexander V. Chernikov# Copyright (c) 2020 Alexander V. Chernikov 634a5582cSAlexander V. Chernikov# 734a5582cSAlexander V. Chernikov# Redistribution and use in source and binary forms, with or without 834a5582cSAlexander V. Chernikov# modification, are permitted provided that the following conditions 934a5582cSAlexander V. Chernikov# are met: 1034a5582cSAlexander V. Chernikov# 1. Redistributions of source code must retain the above copyright 1134a5582cSAlexander V. Chernikov# notice, this list of conditions and the following disclaimer. 1234a5582cSAlexander V. Chernikov# 2. Redistributions in binary form must reproduce the above copyright 1334a5582cSAlexander V. Chernikov# notice, this list of conditions and the following disclaimer in the 1434a5582cSAlexander V. Chernikov# documentation and/or other materials provided with the distribution. 1534a5582cSAlexander V. Chernikov# 1634a5582cSAlexander V. Chernikov# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1734a5582cSAlexander V. Chernikov# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1834a5582cSAlexander V. Chernikov# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1934a5582cSAlexander V. Chernikov# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2034a5582cSAlexander V. Chernikov# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2134a5582cSAlexander V. Chernikov# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2234a5582cSAlexander V. Chernikov# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2334a5582cSAlexander V. Chernikov# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2434a5582cSAlexander V. Chernikov# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2534a5582cSAlexander V. Chernikov# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2634a5582cSAlexander V. Chernikov# SUCH DAMAGE. 2734a5582cSAlexander V. Chernikov# 2834a5582cSAlexander V. Chernikov# 2934a5582cSAlexander V. Chernikov 3034a5582cSAlexander V. Chernikovimport argparse 31*d234b011SKristof Provostimport logging 32*d234b011SKristof Provostlogging.getLogger("scapy").setLevel(logging.CRITICAL) 3334a5582cSAlexander V. Chernikovimport scapy.all as sc 3434a5582cSAlexander V. Chernikovimport socket 3534a5582cSAlexander V. Chernikovimport sys 3634a5582cSAlexander V. Chernikovimport fcntl 3734a5582cSAlexander V. Chernikovimport struct 3834a5582cSAlexander V. Chernikov 3934a5582cSAlexander V. Chernikov 4034a5582cSAlexander V. Chernikovdef parse_args(): 4134a5582cSAlexander V. Chernikov parser = argparse.ArgumentParser(description='ICMP redirect generator') 4234a5582cSAlexander V. Chernikov parser.add_argument('--smac', type=str, required=True, 4334a5582cSAlexander V. Chernikov help='eth source mac') 4434a5582cSAlexander V. Chernikov parser.add_argument('--dmac', type=str, required=True, 4534a5582cSAlexander V. Chernikov help='eth dest mac') 4634a5582cSAlexander V. Chernikov parser.add_argument('--sip', type=str, required=True, 4734a5582cSAlexander V. Chernikov help='remote router source ip') 4834a5582cSAlexander V. Chernikov parser.add_argument('--dip', type=str, required=True, 4934a5582cSAlexander V. Chernikov help='local router ip') 5034a5582cSAlexander V. Chernikov parser.add_argument('--iface', type=str, required=True, 5134a5582cSAlexander V. Chernikov help='ifname to send packet to') 5234a5582cSAlexander V. Chernikov parser.add_argument('--route', type=str, required=True, 5334a5582cSAlexander V. Chernikov help='destination IP to redirect') 5434a5582cSAlexander V. Chernikov parser.add_argument('--gw', type=str, required=True, 5534a5582cSAlexander V. Chernikov help='redirect GW') 5634a5582cSAlexander V. Chernikov return parser.parse_args() 5734a5582cSAlexander V. Chernikov 5834a5582cSAlexander V. Chernikov 5934a5582cSAlexander V. Chernikovdef construct_icmp_redirect(smac, dmac, sip, dip, route_dst, route_gw): 6034a5582cSAlexander V. Chernikov e = sc.Ether(src=smac, dst=dmac) 6134a5582cSAlexander V. Chernikov l3 = sc.IP(src=sip, dst=dip) 6234a5582cSAlexander V. Chernikov icmp = sc.ICMP(type=5, code=1, gw=route_gw) 6334a5582cSAlexander V. Chernikov orig_ip = sc.IP(src=sip, dst=route_dst) 6434a5582cSAlexander V. Chernikov return e / l3 / icmp / orig_ip / sc.UDP() 6534a5582cSAlexander V. Chernikov 6634a5582cSAlexander V. Chernikov 6734a5582cSAlexander V. Chernikovdef send_packet(pkt, iface, feedback=False): 6834a5582cSAlexander V. Chernikov if feedback: 6934a5582cSAlexander V. Chernikov # Make kernel receive the packet as well 7034a5582cSAlexander V. Chernikov BIOCFEEDBACK = 0x8004427c 7134a5582cSAlexander V. Chernikov socket = sc.conf.L2socket(iface=args.iface) 7234a5582cSAlexander V. Chernikov fcntl.ioctl(socket.ins, BIOCFEEDBACK, struct.pack('I', 1)) 7334a5582cSAlexander V. Chernikov sc.sendp(pkt, socket=socket, verbose=True) 7434a5582cSAlexander V. Chernikov else: 7534a5582cSAlexander V. Chernikov sc.sendp(pkt, iface=iface, verbose=False) 7634a5582cSAlexander V. Chernikov 7734a5582cSAlexander V. Chernikov 7834a5582cSAlexander V. Chernikovdef main(): 7934a5582cSAlexander V. Chernikov args = parse_args() 8034a5582cSAlexander V. Chernikov pkt = construct_icmp_redirect(args.smac, args.dmac, args.sip, args.dip, 8134a5582cSAlexander V. Chernikov args.route, args.gw) 8234a5582cSAlexander V. Chernikov send_packet(pkt, args.iface) 8334a5582cSAlexander V. Chernikov 8434a5582cSAlexander V. Chernikov 8534a5582cSAlexander V. Chernikovif __name__ == '__main__': 8634a5582cSAlexander V. Chernikov main() 87