问题
I am trying to use the program DigiKey have made for their Amazon Dash Button hack to monitor for when the button is pressed and then send a HTTP GET to IFTTT. I am using a Raspberry Pi to run this. Source:
import socket
import struct
import binascii
import time
import json
import urllib2
# Use your own IFTTT key
ifttt_key = 'example_key'
# Set these up at https://ifttt.com/maker
ifttt_url_button = 'https://maker.ifttt.com/trigger/button_pressed/with/key/' + ifttt_key
# Replace this MAC addresses and nickname with your own
macs = {
'xxxxxxxxxxxx' : 'vanish'
}
# Trigger a IFTTT URL. Body includes JSON with timestamp values.
def trigger_url(url):
data = '{ "value1" : "' + time.strftime("%Y-%m-%d") + '", "value2" : "' + time.strftime("%H:%M") + '" }'
req = urllib2.Request(url, data, {'Content-Type': 'application/json'})
f = urllib2.urlopen(req)
response = f.read()
f.close()
return response
def button_pressed():
print 'triggering button event, response:' + trigger_url(ifttt_url_button)
rawSocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.htons(0x0003))
while True:
packet = rawSocket.recvfrom(2048)
ethernet_header = packet[0][0:14]
ethernet_detailed = struct.unpack("!6s6s2s", ethernet_header)
# skip non-ARP packets
ethertype = ethernet_detailed[2]
if ethertype != '\x08\x06':
continue
# read out data
arp_header = packet[0][14:42]
arp_detailed = struct.unpack("2s2s1s1s2s6s4s6s4s", arp_header)
source_mac = binascii.hexlify(arp_detailed[5])
source_ip = socket.inet_ntoa(arp_detailed[6])
dest_ip = socket.inet_ntoa(arp_detailed[8])
if source_mac in macs:
#print "ARP from " + macs[source_mac] + " with IP " + source_ip
if macs[source_mac] == 'vanish':
button_pressed()
else:
print "Unknown MAC " + source_mac + " from IP " + source_ip
The error I receive is:
Traceback (most recent call last):
File "/home/pi/Desktop/dash_btn.py", line 30, in <module>
rawSocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.htons(0x0003))
File "/usr/lib/python2.7/socket.py", line 187, in __init__
_sock = _realsocket(family, type, proto)
error: [Errno 1] Operation not permitted
I have tried running it in the terminal with sudo , but it hasn't changed anything. Help would be appreciated.
回答1:
Since you wish to receive and parse ARP packets (which are on a link layer, OSI layer 2, below IP level you receive with AF_INET
), you'll have to use the low-level packet interface, AF_PACKET
.
From man packet
(for AF_PACKET
sockets):
The socket_type is either
SOCK_RAW
for raw packets including the link-level header orSOCK_DGRAM
for cooked packets with the link-level header removed. The link-level header information is available in a common format in asockaddr_ll
structure. protocol is the IEEE 802.3 protocol number in network byte order. See the<linux/if_ether.h>
include file for a list of allowed protocols. When protocol is set tohtons(ETH_P_ALL)
, then all protocols are received. All incoming packets of that protocol type will be passed to the packet socket before they are passed to the protocols implemented in the kernel.
So, for sniffing ARP packets, you must use SOCK_RAW
socket type. However, to use it, from man 7 raw
:
Only processes with an effective user ID of 0 or the CAP_NET_RAW capability are allowed to open raw sockets.
therefore, you'll have to run your program with sudo
.
For socket protocol (third parameter) you might choose 0x0003
as you already have, which means ETH_P_ALL
, receiving all packages, or probably better, ETH_P_ARP
which has a value of 0x0806
(see your /usr/include/linux/if_ether.h
) to receive only ARP packages.
All taken together, this looks like this:
rawSocket = socket.socket(socket.AF_PACKET, socket.SOCK_RAW, socket.htons(0x0806))
while True:
packet = rawSocket.recvfrom(2048)
# no need to filter-out ARP
# less load on user program
来源:https://stackoverflow.com/questions/45127645/errno-1-operation-not-permitted-when-creating-socket