1*4a64e381SAndroid Build Coastguard Worker#!/usr/bin/env python3 2*4a64e381SAndroid Build Coastguard Worker# 3*4a64e381SAndroid Build Coastguard Worker# Copyright (c) 2021, The OpenThread Authors. 4*4a64e381SAndroid Build Coastguard Worker# All rights reserved. 5*4a64e381SAndroid Build Coastguard Worker# 6*4a64e381SAndroid Build Coastguard Worker# Redistribution and use in source and binary forms, with or without 7*4a64e381SAndroid Build Coastguard Worker# modification, are permitted provided that the following conditions are met: 8*4a64e381SAndroid Build Coastguard Worker# 1. Redistributions of source code must retain the above copyright 9*4a64e381SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer. 10*4a64e381SAndroid Build Coastguard Worker# 2. Redistributions in binary form must reproduce the above copyright 11*4a64e381SAndroid Build Coastguard Worker# notice, this list of conditions and the following disclaimer in the 12*4a64e381SAndroid Build Coastguard Worker# documentation and/or other materials provided with the distribution. 13*4a64e381SAndroid Build Coastguard Worker# 3. Neither the name of the copyright holder nor the 14*4a64e381SAndroid Build Coastguard Worker# names of its contributors may be used to endorse or promote products 15*4a64e381SAndroid Build Coastguard Worker# derived from this software without specific prior written permission. 16*4a64e381SAndroid Build Coastguard Worker# 17*4a64e381SAndroid Build Coastguard Worker# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 18*4a64e381SAndroid Build Coastguard Worker# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*4a64e381SAndroid Build Coastguard Worker# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*4a64e381SAndroid Build Coastguard Worker# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 21*4a64e381SAndroid Build Coastguard Worker# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22*4a64e381SAndroid Build Coastguard Worker# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23*4a64e381SAndroid Build Coastguard Worker# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24*4a64e381SAndroid Build Coastguard Worker# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25*4a64e381SAndroid Build Coastguard Worker# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26*4a64e381SAndroid Build Coastguard Worker# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27*4a64e381SAndroid Build Coastguard Worker# POSSIBILITY OF SUCH DAMAGE. 28*4a64e381SAndroid Build Coastguard Worker# 29*4a64e381SAndroid Build Coastguard Worker# 30*4a64e381SAndroid Build Coastguard Worker# This script generates and sends MLD Query message on the given interface. 31*4a64e381SAndroid Build Coastguard Worker# 32*4a64e381SAndroid Build Coastguard Worker# Multicast Listener Query Message (RFC3810): 33*4a64e381SAndroid Build Coastguard Worker# 34*4a64e381SAndroid Build Coastguard Worker# 0 1 2 3 35*4a64e381SAndroid Build Coastguard Worker# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 36*4a64e381SAndroid Build Coastguard Worker# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 37*4a64e381SAndroid Build Coastguard Worker# | Type = 130 | Code | Checksum | 38*4a64e381SAndroid Build Coastguard Worker# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 39*4a64e381SAndroid Build Coastguard Worker# | Maximum Response Code | Reserved | 40*4a64e381SAndroid Build Coastguard Worker# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 41*4a64e381SAndroid Build Coastguard Worker# | | 42*4a64e381SAndroid Build Coastguard Worker# * * 43*4a64e381SAndroid Build Coastguard Worker# | | 44*4a64e381SAndroid Build Coastguard Worker# * Multicast Address * 45*4a64e381SAndroid Build Coastguard Worker# | | 46*4a64e381SAndroid Build Coastguard Worker# * * 47*4a64e381SAndroid Build Coastguard Worker# | | 48*4a64e381SAndroid Build Coastguard Worker# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 49*4a64e381SAndroid Build Coastguard Worker# | Resv |S| QRV | QQIC | Number of Sources (N) | 50*4a64e381SAndroid Build Coastguard Worker# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 51*4a64e381SAndroid Build Coastguard Worker# 52*4a64e381SAndroid Build Coastguard Worker# IPv6 Router Alert option (RFC2711) in a Hop-by-Hop Options header: 53*4a64e381SAndroid Build Coastguard Worker# 54*4a64e381SAndroid Build Coastguard Worker# 0 1 2 3 55*4a64e381SAndroid Build Coastguard Worker# 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 56*4a64e381SAndroid Build Coastguard Worker# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 57*4a64e381SAndroid Build Coastguard Worker# | Next Header | Hdr Ext Len |0 0 0|0 0 1 0 1|0 0 0 0 0 0 1 0| 58*4a64e381SAndroid Build Coastguard Worker# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 59*4a64e381SAndroid Build Coastguard Worker# | Value (2 octets) | PadN | 60*4a64e381SAndroid Build Coastguard Worker# +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 61*4a64e381SAndroid Build Coastguard Worker# 62*4a64e381SAndroid Build Coastguard Worker 63*4a64e381SAndroid Build Coastguard Workerimport sys 64*4a64e381SAndroid Build Coastguard Workerimport socket 65*4a64e381SAndroid Build Coastguard Workerimport syslog 66*4a64e381SAndroid Build Coastguard Workerimport struct 67*4a64e381SAndroid Build Coastguard Worker 68*4a64e381SAndroid Build Coastguard WorkerICMP6_TYPE_MLD_QUERY = 130 69*4a64e381SAndroid Build Coastguard WorkerIPV6_EXT_HBH_ROUTER_ALERT = 5 70*4a64e381SAndroid Build Coastguard Worker 71*4a64e381SAndroid Build Coastguard Workerdef main(): 72*4a64e381SAndroid Build Coastguard Worker interface = sys.argv[1] 73*4a64e381SAndroid Build Coastguard Worker dst = sys.argv[2] 74*4a64e381SAndroid Build Coastguard Worker 75*4a64e381SAndroid Build Coastguard Worker log = '====otbr-agent=send_mld_query=== send_mld_query.py started' 76*4a64e381SAndroid Build Coastguard Worker syslog.syslog(syslog.LOG_ERR, log) 77*4a64e381SAndroid Build Coastguard Worker print(log) 78*4a64e381SAndroid Build Coastguard Worker 79*4a64e381SAndroid Build Coastguard Worker log = 'interface %s' % interface 80*4a64e381SAndroid Build Coastguard Worker syslog.syslog(syslog.LOG_ERR, log) 81*4a64e381SAndroid Build Coastguard Worker print(log) 82*4a64e381SAndroid Build Coastguard Worker 83*4a64e381SAndroid Build Coastguard Worker log = 'dst %s' % dst 84*4a64e381SAndroid Build Coastguard Worker syslog.syslog(syslog.LOG_ERR, log) 85*4a64e381SAndroid Build Coastguard Worker print(log) 86*4a64e381SAndroid Build Coastguard Worker 87*4a64e381SAndroid Build Coastguard Worker try: 88*4a64e381SAndroid Build Coastguard Worker sock = socket.socket(socket.AF_INET6, socket.SOCK_RAW, socket.IPPROTO_ICMPV6) 89*4a64e381SAndroid Build Coastguard Worker 90*4a64e381SAndroid Build Coastguard Worker # Configure SO_BINDTODEVICE to bind the network interface. 91*4a64e381SAndroid Build Coastguard Worker sock.setsockopt(socket.SOL_SOCKET, 25, interface.encode('utf-8')) 92*4a64e381SAndroid Build Coastguard Worker sock.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_HOPS, 1) 93*4a64e381SAndroid Build Coastguard Worker 94*4a64e381SAndroid Build Coastguard Worker # Build ICMPv6 MLD Query message header 95*4a64e381SAndroid Build Coastguard Worker query = struct.pack("B", ICMP6_TYPE_MLD_QUERY) # Type: 130 96*4a64e381SAndroid Build Coastguard Worker query += struct.pack("B", 0) # Code 97*4a64e381SAndroid Build Coastguard Worker query += struct.pack("!H", 0) # Checksum 98*4a64e381SAndroid Build Coastguard Worker 99*4a64e381SAndroid Build Coastguard Worker # Query Response Interval: 10 seconds (RFC 3810, section 9.3) 100*4a64e381SAndroid Build Coastguard Worker query += struct.pack("!H", 10000) 101*4a64e381SAndroid Build Coastguard Worker 102*4a64e381SAndroid Build Coastguard Worker # Reserved field 103*4a64e381SAndroid Build Coastguard Worker query += struct.pack("!H", 0) 104*4a64e381SAndroid Build Coastguard Worker 105*4a64e381SAndroid Build Coastguard Worker # Multicast address (unspecified) 106*4a64e381SAndroid Build Coastguard Worker query += struct.pack("!16s", ''.encode()) 107*4a64e381SAndroid Build Coastguard Worker 108*4a64e381SAndroid Build Coastguard Worker # Querier's Robustness Variable: 2 (RFC 3810, section 9.1) 109*4a64e381SAndroid Build Coastguard Worker query += struct.pack("B", 2) 110*4a64e381SAndroid Build Coastguard Worker 111*4a64e381SAndroid Build Coastguard Worker # Querier's Query Interval Code: 125 (RFC 3810, section 9.2) 112*4a64e381SAndroid Build Coastguard Worker query += struct.pack("B", 125) 113*4a64e381SAndroid Build Coastguard Worker 114*4a64e381SAndroid Build Coastguard Worker # Number of sources 115*4a64e381SAndroid Build Coastguard Worker query += struct.pack("!H", 0) 116*4a64e381SAndroid Build Coastguard Worker 117*4a64e381SAndroid Build Coastguard Worker # Build IPv6 Hop-by-Hop header 118*4a64e381SAndroid Build Coastguard Worker ext_hdr = struct.pack("B", socket.getprotobyname('ipv6-icmp')) 119*4a64e381SAndroid Build Coastguard Worker ext_hdr += struct.pack("B", 0) 120*4a64e381SAndroid Build Coastguard Worker 121*4a64e381SAndroid Build Coastguard Worker # Include Router Alert option (RFC 2711) 122*4a64e381SAndroid Build Coastguard Worker ext_hdr += struct.pack("B", IPV6_EXT_HBH_ROUTER_ALERT) 123*4a64e381SAndroid Build Coastguard Worker ext_hdr += struct.pack("B", 2) # Length 124*4a64e381SAndroid Build Coastguard Worker ext_hdr += struct.pack("!H", 0) # MLD message 125*4a64e381SAndroid Build Coastguard Worker 126*4a64e381SAndroid Build Coastguard Worker # Insert PadN option to keep alignment (2-bytes) 127*4a64e381SAndroid Build Coastguard Worker ext_hdr += struct.pack("B", 1) 128*4a64e381SAndroid Build Coastguard Worker ext_hdr += struct.pack("B", 0) 129*4a64e381SAndroid Build Coastguard Worker 130*4a64e381SAndroid Build Coastguard Worker # Send MLD Query message 131*4a64e381SAndroid Build Coastguard Worker sock.sendmsg([query], [(socket.IPPROTO_IPV6, socket.IPV6_HOPOPTS, ext_hdr)], 0, (dst, 0, 0)) 132*4a64e381SAndroid Build Coastguard Worker 133*4a64e381SAndroid Build Coastguard Worker except Exception as e: 134*4a64e381SAndroid Build Coastguard Worker log = '====otbr-agent=send_mld_query=== sendmsg %s' % str(e) 135*4a64e381SAndroid Build Coastguard Worker syslog.syslog(syslog.LOG_ERR, log) 136*4a64e381SAndroid Build Coastguard Worker print(log) 137*4a64e381SAndroid Build Coastguard Worker 138*4a64e381SAndroid Build Coastguard Worker sock.close() 139*4a64e381SAndroid Build Coastguard Worker log = '====otbr-agent=send_mld_query=== close' 140*4a64e381SAndroid Build Coastguard Worker syslog.syslog(syslog.LOG_ERR, log) 141*4a64e381SAndroid Build Coastguard Worker print(log) 142*4a64e381SAndroid Build Coastguard Worker 143*4a64e381SAndroid Build Coastguard Workerif __name__ == '__main__': 144*4a64e381SAndroid Build Coastguard Worker main() 145