mark pod.py as running on python2
[pingofdeath.git] / pod.py
1 #! /usr/bin/env python2
2 #
3 # Marc E. Fiuczynski <mef@cs.princeton.edu>
4 # Copyright (C) 2004 The Trustees of Princeton University
5 #
6 # Client ping of death program for both udp & icmp
7
8 import sys
9 import struct
10 import os
11 import array
12 import getopt
13 from socket import *
14
15 def usage():
16     sys.stdout = sys.stderr
17     print 'Usage: pod -i identityfile [--icmp,--udp] hostnamelist'
18     print ' -i identity  key where key may be - for stdin'
19     print ' --icmp icmp protocol only'
20     print ' --udp udp protocol only'
21     print ' by default both icmp and udp are used'
22
23
24 UPOD_PORT = 664
25
26 def _in_cksum(packet):
27     """THE RFC792 states: 'The 16 bit one's complement of
28     the one's complement sum of all 16 bit words in the header.'
29     Generates a checksum of a (ICMP) packet. Based on in_chksum found
30     in ping.c on FreeBSD.
31     """
32
33     # add byte if not dividable by 2
34     if len(packet) & 1:
35         packet = packet + '\0'
36
37     # split into 16-bit word and insert into a binary array
38     words = array.array('h', packet)
39     sum = 0
40
41     # perform ones complement arithmetic on 16-bit words
42     for word in words:
43         sum += (word & 0xffff)
44
45     hi = sum >> 16
46     lo = sum & 0xffff
47     sum = hi + lo
48     sum = sum + (sum >> 16)
49
50     return (~sum) & 0xffff # return ones complement
51
52 def _construct(id, data):
53     """Constructs a ICMP IPOD packet
54     """
55     ICMP_TYPE = 6 # ping of death code used by PLK
56     ICMP_CODE = 0
57     ICMP_CHECKSUM = 0
58     ICMP_ID = 0
59     ICMP_SEQ_NR = 0
60
61     header = struct.pack('bbHHh', ICMP_TYPE, ICMP_CODE, ICMP_CHECKSUM, \
62                          ICMP_ID, ICMP_SEQ_NR+id)
63
64     packet = header + data          # ping packet without checksum
65     checksum = _in_cksum(packet)    # make checksum
66
67     # construct header with correct checksum
68     header = struct.pack('bbHHh', ICMP_TYPE, ICMP_CODE, checksum, ICMP_ID, \
69                          ICMP_SEQ_NR+id)
70
71     # ping packet *with* checksum
72     packet = header + data
73
74     # a perfectly formatted ICMP echo packet
75     return packet
76
77 def icmp_pod(host,key):
78     uid = os.getuid()
79     if uid <> 0:
80         print "must be root to send icmp pod"
81         return
82     
83     s = socket(AF_INET, SOCK_RAW, getprotobyname("icmp"))
84     packet = _construct(0, key) # make a ping packet
85     addr = (host,1)
86     print 'pod sending icmp-based reboot request to %s' % host
87     for i in range(1,10):
88         s.sendto(packet, addr)
89
90 def udp_pod(host,key):
91     addr = host, UPOD_PORT
92     s = socket(AF_INET, SOCK_DGRAM)
93     s.bind(('', 0))
94     packet = key
95     print 'pod sending udp-based reboot request to %s' % host
96     for i in range(1,10):
97         s.sendto(packet, addr)
98
99 def noop_pod(host,key):
100     pass
101
102 def main():
103     try:
104         opts, args = getopt.getopt(sys.argv[1:], "i:", ["icmp","udp"])
105     except getops.GetoptError:
106         usage()
107         sys.exit(2)
108         
109     hosts = args
110     protos = {'udp' : udp_pod, 'icmp' : icmp_pod}
111     key = None
112     for o, a in opts:
113         if o == "--icmp":
114             del protos['udp']
115         if o == "--udp":
116             del protos['icmp']
117         if o == "-i":
118             if len(a)==1 and a[0]=='-':
119                 key = sys.stdin.readline()
120             else:
121                 try:
122                     f = open(a)
123                     key = f.readline()
124                     key = k[:32]
125                     f.close()
126                 except:
127                     print '%s not found' % a
128                     usage()
129                     sys.exit(2)
130
131     if key is None:
132         usage()
133         sys.exit(2)
134
135     protocols = ['udp','icmp']
136     for host in hosts:
137         for protocol in protocols:
138             pod = protos.get(protocol,noop_pod)
139             pod(host,key)
140
141 if __name__ == '__main__':
142     main()