How can I utilize scapy as a dhcp client to request certain DHCP options? Clients will request what they need and a dhcp client should respond accordingly. However, I need to test if certain DHCP options are being sent from a server and these are options my PC won't normally request. These could be options 150, 242, etc.
Can scapy support any of the DHCP options? In the code below, how would I adjust if I wanted to request option 242 or option 150?
ethernet = Ether(dst='ff:ff:ff:ff:ff:ff',src=src_mac_address,type=0x800)
ip = IP(src ='0.0.0.0',dst='255.255.255.255')
udp =UDP (sport=68,dport=67)
bootp = BOOTP(chaddr = hw, ciaddr = '0.0.0.0',xid = 0x01020304,flags= 1)
dhcp = DHCP(options=[("message-type","discover"),"end"])
packet = ethernet / ip / udp / bootp / dhcp
requested_option_1 = 1 # Subnet Mask
requested_option_2 = 6 # Domain Name Servers
requested_option_3 = 15 # Domain Name
requested_option_4 = 44 # NetBIOS (TCP/IP) Name Servers
requested_option_5 = 3 # Routers
requested_option_6 = 33 # Static Routes
requested_option_7 = 150 # TFTP Server address
requested_option_8 = 43 # Vendor Specific Information
bytes_requested_options = struct.pack("8B", requested_option_1,
requested_option_2,
requested_option_3,
requested_option_4,
requested_option_5,
requested_option_6,
requested_option_7,
requested_option_8)
dhcp = DHCP(options=[('message-type', 'discover'),('param_req_list',bytes_requested_options),'end'])
Simply add your options as a integer array, like this:
dhcp = DHCP(options=[('message-type','discover'),
('hostname',hostname),
('param_req_list',
[1,3,6]),
('end')])
Or, in order to use the scapy provided options:
dhcp = DHCP(options=[('message-type','discover'),
('hostname',hostname),
('param_req_list',
[
int(scapy.all.DHCPRevOptions["subnet_mask"][0]),
int(scapy.all.DHCPRevOptions["router"][0]),
int(scapy.all.DHCPRevOptions["name_server"][0])
]),
('end')])
Related
I am trying to use scapy to send and receive packets to discover the network path. I would like to modify the packet details when it reaches a certain hop due to tunnels. For some reason, sniff is not matching on ICMP packets received. TCPDUMP on the clone session shows the ICMP packet was received on the sniff interface.
while lasthop:
outer_ttl = outer_ttl + 1
inner = IP(src=sw3, dst=sw3, flags="DF", ttl=inner_ttl, id=id) / UDP(sport=37631, dport=33435)
outer = IP(src=sw1, dst=sw2, flags="DF", ttl=outer_ttl, id=id) / GRE() / inner
if sniff(iface="ens1", count=1, filter="icmp and icmp[0]=11 and src host 10.1.1.1", prn=send(outer), timeout=1):
inner_ttl = 2
send(outer)
lasthop = 0
I tried sniff from the scapy console. Its the same problem. But interestingly it matches if i run traceroute for a clone session.
I want to create streaming videos by using a socket. I need to know how I can find the port number address.
My code that I wrote to create a client:
# create socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host_ip = '192.168.0.165' # paste your server ip address here
port =
client_socket.connect((host_ip, port)) # a tuple
data = b""
payload_size = struct.calcsize("Q") # Q: unsigned long long integer(8 bytes)
Can you post the code from your service app? (or name the service app) Usually you declare the port in the service somewhere. If its prebuilt, it could be in a configuration file.
You can run cmd.exe and type netstat to check your port activity. Or go to your firewalls inbound/outbound rules. Typically if its a prebuilt app it will create a firewall rule with associated port so the firewall does not freak out when connections come in to that port.
But otherwise there is not enough information here for me to give a complete answer.
I have a raspberry pi that is both connected to the internet via Wlan and a local device via Ethernet. So it has two IPs; one for each endpoint.
This is how it looks like simplified when running ifconfig; with different IPs for privacy
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 189.168.200.110 netmask 0.0.0.0 broadcast 255.255.255.255
wlan0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 189.168.201.79 netmask 255.255.255.0 broadcast 192.168.1.255
This is the code that python is using to send a message to the device through the Ethernet with that gateway's ip
TCP_PORT = 3001
SERVER_IP_AD = "189.168.200.110"
CLIENT_IP_AD = "189.168.200.155"
BROADCAST_IP = "255.255.255.255"
def sendMessage(self, file_path, client_ip=CLIENT_IP_AD):
print('message en route')
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind((self.SERVER_IP_AD, 0))
s.connect((client_ip, self.TCP_PORT)) #**ERROR IS HERE**
MESSAGE = self.openFile(file_path)
s.send(MESSAGE.encode())
data = s.recv(self.BUFFER_SIZE)
s.close()
return data
Using wireshark I can see that the package is being sent through the Wlan interface instead of the Ethernet interface with the correct IP source and IP destination.
How do I tell python to use the correct interface when sending out the package?
In my opinion, you can establish Tcp connection with Ethernet, cause there isn't shaking hands by Ethernet
And, you shouldn't use s.bind() and s.connect() at the same time. Because the former is for UDP client, and the later is for TCP client. Have a try with only s.bind().
The Linux/Windows can get DNS address from the router
I need to write a local dns proxy and how can I get the DNS server addresses like the OS does, are there any Perl or Python modules can do this?
Update
The question should be clear, I need some thing to simulate the interface start and the protocol talking with local router, I can not take a tcpdump before a interface starts. Not sure if there is an sample trace file on internet. Possiblely it's not IP protocol which I am not familiar with.
Update2
As I use local DNS proxy server, the TCP configuration is like showing in picture
If I query Net::DNS::Resolver, I get result: 127.0.0.1 which is not what I needed
Really long, formatted comment supporting Steffen's answer.
TLDR: Steffen is correct (+1 BTW). Net::DNS::Resolver should get you the information you need.
Example:
#!perl
use strict;
use warnings;
use Net::DNS::Resolver;
#configure a resolver object using your OS's current config.
my $resolver = Net::DNS::Resolver->new;
print join "\n", $resolver->nameservers;
Tested on Windows & OS X.
If you are serous in your quest for the rope to hang yourself, the protocol you're asking about is DHCP (Dynamic Host Configuration Protocol).
Using DHCP like your OS does, is not a mere "Query" for DNS servers, but a request for a (new/renewed) lease of an IP Address. The fact that things like Gateway, Time Servers & DNS Servers are included are also important, but secondary. If done incorrectly, you may either screw up the relationship between your OS and the DHCP server or convince your DHCP server that your program is another (false) machine on the network for which it should maintain lease information.
gethostbyname uses the resolver function of the underlying OS library. If you want to have more direct access to the DNS packets use Net::DNS::Resolver.
inspired by Steffen Ullrich
I got the issue resolved, by managed taking a DHCP trace and simulated by Net::DHCP::Packet, fortunately it's simple UDP protocol
You need to findout IP/Mac/GW address before using the script
#!/usr/bin/perl
use strict;
use warnings;
use IO::Socket::INET;
use Net::DHCP::Packet;
use Net::DHCP::Constants;
srand();
# creat DHCP Packet
my $discover = Net::DHCP::Packet->new(
Xid => int(rand(0xFFFFFFFF)), # random xid
Flags => 0x0000,
DHO_DHCP_MESSAGE_TYPE() => DHCPREQUEST(),
);
$discover->ciaddr('192.168.1.5');
$discover->chaddr('5cc5d43ca078');
my $handle = IO::Socket::INET->new(
Proto => 'udp',
ReuseAddr => 1,
PeerPort => '67',
LocalPort => '68',
PeerAddr => '192.168.1.1'
) or die "socket: $#";
$handle->send($discover->serialize());
my $newmsg;
if ($handle->recv($newmsg, 1024)) {
my $packet = Net::DHCP::Packet->new($newmsg);
print STDERR $packet->toString();
}
Execution result:
op = BOOTREPLY
htype = HTYPE_ETHER
hlen = 6
hops = 0
xid = eaba416c
secs = 0
flags = 0
ciaddr = 192.168.1.5
yiaddr = 192.168.1.5
siaddr = 0.0.0.0
giaddr = 0.0.0.0
chaddr = 5cc5d43ca078
sname =
file =
Options :
DHO_DHCP_MESSAGE_TYPE(53) = DHCPACK
DHO_SUBNET_MASK(1) = 255.255.255.0
DHO_ROUTERS(3) = 192.168.1.1
DHO_DOMAIN_NAME_SERVERS(6) = 192.168.1.1
DHO_DHCP_SERVER_IDENTIFIER(54) = 192.168.1.1
DHO_DHCP_LEASE_TIME(51) = 86400
DHO_VI_VENDOR_SPECIFIC_INFOMATION(125) = \x00\x00\x00\x00\x14\x02\x06HGW-CT\x0A\x02\x00\x00\x0B\x02\x00U\x0D\x02\x00.
padding [247] = 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
We can see
DHO_DOMAIN_NAME_SERVERS(6) = 192.168.1.1
Is the DNS server address
tcmpdump can view all the multicast traffic to specific group and port on eth2, but my Python program cannot. The Python program, running on Ubuntu 12.04:
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
# Multicast port is 52122
sock.bind(('', 52122))
# Interface eth2 IP is 1.2.3.4, multicast group is 6.7.8.9
mreq = socket.inet_aton('6.7.8.9')+socket.inet_aton('1.2.3.4')
sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
while True:
print '\nwaiting to receive message'
data, address = sock.recvfrom(1024)
print data
When I use another program to send a multicast packet to eth2, it works and prints the packet. But it fails to see all the current multicast traffic. If I run tcpdump on eth2 on the same port and group as the above program:
sudo tcpdump -i eth2 host 6.7.8.9 and port 52122
it sees both the packets I send from another program AND all the current multicast traffic. It's output looks likes this...
# Packet sent from my other program
09:52:51.952714 IP 1.2.3.4.57940 > 6.7.8.9.52122: UDP, length 19
# Packet send from the outside world
09:52:52.143339 IP 9.9.9.9.39295 > 6.7.8.9.52122: UDP, length 62
Why can't my program see the packets from the outside world? How can I modify it (or something else) to fix this?
Edit:
I should have mentioned, the interface this going over is not eth2 but eth2.200 a VLAN. (The local IP and the tcpdump commands are all run with eth2.200, I just changed that in this question to make it simpler.) Based on this answer that could be the problem?
Edit #2:
netstat -ng when the program is running shows eth2.200 subscribed to 224.0.0.1 and 6.7.8.9`.
tshark -i eth2.200 igmp shows three repeated 1.2.3.4 -> 6.7.8.9 IGMP 46 V2 Membership Report / Join group 6.7.8.9 when the program first starts. When the program process is killed, it shows 1.2.3.4 -> 224.0.0.2 IGMP 46 V2 Leave group 6.7.8.9. There is also an infrequent 1.2.3.1 -> 224.0.0.1 IGMP 60 V2 Membership Query, general, where 1.2.3.1 is 1.2.3.4's gateway.
Not sure if it will help, but the routing table looks like:
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 1.2.5.6 0.0.0.0 UG 0 0 0 eth1
1.2.3.0 0.0.0.0 255.255.255.240 U 0 0 0 eth2.200
Thank you!
Finally! Found this question on ServerFault that addresses the same thing. Basically the kernel was not forwarding on / was filtering out the packets because it thought the sourced address was spoofed.
Changed the settings in /etc/sysctl.conf to match:
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.ip_forward = 1
Rebooted and everything works.