2dd596d15c436eb5958878eecb8bded5a995f21d
[plcapi.git] / PLC / POD.py
1 # $Id$
2 # Marc E. Fiuczynski <mef@cs.princeton.edu>
3 # Copyright (C) 2004 The Trustees of Princeton University
4 #
5 # Client ping of death program for both udp & icmp
6 #
7 # modified for inclusion by api by Aaron K
8
9 import struct
10 import os
11 import array
12 import getopt
13 from socket import *
14
15 UPOD_PORT = 664
16
17 def _in_cksum(packet):
18     """THE RFC792 states: 'The 16 bit one's complement of
19     the one's complement sum of all 16 bit words in the header.'
20     Generates a checksum of a (ICMP) packet. Based on in_chksum found
21     in ping.c on FreeBSD.
22     """
23
24     # add byte if not dividable by 2
25     if len(packet) & 1:
26         packet = packet + '\0'
27
28     # split into 16-bit word and insert into a binary array
29     words = array.array('h', packet)
30     sum = 0
31
32     # perform ones complement arithmetic on 16-bit words
33     for word in words:
34         sum += (word & 0xffff)
35
36     hi = sum >> 16
37     lo = sum & 0xffff
38     sum = hi + lo
39     sum = sum + (sum >> 16)
40
41     return (~sum) & 0xffff # return ones complement
42
43 def _construct(id, data):
44     """Constructs a ICMP IPOD packet
45     """
46     ICMP_TYPE = 6 # ping of death code used by PLK
47     ICMP_CODE = 0
48     ICMP_CHECKSUM = 0
49     ICMP_ID = 0
50     ICMP_SEQ_NR = 0
51
52     header = struct.pack('bbHHh', ICMP_TYPE, ICMP_CODE, ICMP_CHECKSUM, \
53                          ICMP_ID, ICMP_SEQ_NR+id)
54
55     packet = header + data          # ping packet without checksum
56     checksum = _in_cksum(packet)    # make checksum
57
58     # construct header with correct checksum
59     header = struct.pack('bbHHh', ICMP_TYPE, ICMP_CODE, checksum, ICMP_ID, \
60                          ICMP_SEQ_NR+id)
61
62     # ping packet *with* checksum
63     packet = header + data
64
65     # a perfectly formatted ICMP echo packet
66     return packet
67
68 def icmp_pod(host,key):
69     uid = os.getuid()
70     if uid <> 0:
71         print "must be root to send icmp pod"
72         return
73     
74     s = socket(AF_INET, SOCK_RAW, getprotobyname("icmp"))
75     packet = _construct(0, key) # make a ping packet
76     addr = (host,1)
77     print 'pod sending icmp-based reboot request to %s' % host
78     for i in range(1,10):
79         s.sendto(packet, addr)
80
81 def udp_pod(host,key,fromaddr=('', 0)):
82     addr = host, UPOD_PORT
83     s = socket(AF_INET, SOCK_DGRAM)
84     s.bind(fromaddr)
85     packet = key
86     print 'pod sending udp-based reboot request to %s' % host
87     for i in range(1,10):
88         s.sendto(packet, addr)
89
90 def noop_pod(host,key):
91     pass