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