├── .gitattributes ├── .gitignore └── PPPoESession.py /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=union 7 | *.csproj merge=union 8 | *.vbproj merge=union 9 | *.fsproj merge=union 10 | *.dbproj merge=union 11 | 12 | # Standard to msysgit 13 | *.doc diff=astextplain 14 | *.DOC diff=astextplain 15 | *.docx diff=astextplain 16 | *.DOCX diff=astextplain 17 | *.dot diff=astextplain 18 | *.DOT diff=astextplain 19 | *.pdf diff=astextplain 20 | *.PDF diff=astextplain 21 | *.rtf diff=astextplain 22 | *.RTF diff=astextplain 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | [Dd]ebug/ 46 | [Rr]elease/ 47 | *_i.c 48 | *_p.c 49 | *.ilk 50 | *.meta 51 | *.obj 52 | *.pch 53 | *.pdb 54 | *.pgc 55 | *.pgd 56 | *.rsp 57 | *.sbr 58 | *.tlb 59 | *.tli 60 | *.tlh 61 | *.tmp 62 | *.vspscc 63 | .builds 64 | *.dotCover 65 | 66 | ## TODO: If you have NuGet Package Restore enabled, uncomment this 67 | #packages/ 68 | 69 | # Visual C++ cache files 70 | ipch/ 71 | *.aps 72 | *.ncb 73 | *.opensdf 74 | *.sdf 75 | 76 | # Visual Studio profiler 77 | *.psess 78 | *.vsp 79 | 80 | # ReSharper is a .NET coding add-in 81 | _ReSharper* 82 | 83 | # Installshield output folder 84 | [Ee]xpress 85 | 86 | # DocProject is a documentation generator add-in 87 | DocProject/buildhelp/ 88 | DocProject/Help/*.HxT 89 | DocProject/Help/*.HxC 90 | DocProject/Help/*.hhc 91 | DocProject/Help/*.hhk 92 | DocProject/Help/*.hhp 93 | DocProject/Help/Html2 94 | DocProject/Help/html 95 | 96 | # Click-Once directory 97 | publish 98 | 99 | # Others 100 | [Bb]in 101 | [Oo]bj 102 | sql 103 | TestResults 104 | *.Cache 105 | ClientBin 106 | stylecop.* 107 | ~$* 108 | *.dbmdl 109 | Generated_Code #added for RIA/Silverlight projects 110 | 111 | # Backup & report files from converting an old project file to a newer 112 | # Visual Studio version. Backup files are not needed, because we have git ;-) 113 | _UpgradeReport_Files/ 114 | Backup*/ 115 | UpgradeLog*.XML 116 | 117 | 118 | 119 | ############ 120 | ## Windows 121 | ############ 122 | 123 | # Windows image file caches 124 | Thumbs.db 125 | 126 | # Folder config file 127 | Desktop.ini 128 | 129 | 130 | ############# 131 | ## Python 132 | ############# 133 | 134 | *.py[co] 135 | 136 | # Packages 137 | *.egg 138 | *.egg-info 139 | dist 140 | build 141 | eggs 142 | parts 143 | bin 144 | var 145 | sdist 146 | develop-eggs 147 | .installed.cfg 148 | 149 | # Installer logs 150 | pip-log.txt 151 | 152 | # Unit test / coverage reports 153 | .coverage 154 | .tox 155 | 156 | #Translations 157 | *.mo 158 | 159 | #Mr Developer 160 | .mr.developer.cfg 161 | 162 | # Mac crap 163 | .DS_Store 164 | -------------------------------------------------------------------------------- /PPPoESession.py: -------------------------------------------------------------------------------- 1 | # 2 | # PPPoESession v0.2, January 2013 3 | # by Foeh Mannay - see http://networkbodges.blogspot.com for more information 4 | # 5 | 6 | import md5 7 | import time 8 | import os 9 | from scapy.all import * 10 | 11 | # Some human-readable versions of hex type numbers 12 | Service_Name = '\x01\x01' 13 | Host_Unique = '\x01\x03' 14 | AC_Cookie = '\x01\x04' 15 | LCP = 49185 16 | CHAP = 49699 17 | IPCP = 32801 18 | IPv4 = 33 19 | PADI = 9 20 | PADO = 7 21 | PADR = 25 22 | PADS = 101 23 | PADT = 167 24 | ConfReq = '\x01' 25 | ConfAck = '\x02' 26 | ConfNak = '\x03' 27 | ConfRej = '\x04' 28 | TermReq = '\x05' 29 | TermAck = '\x06' 30 | EchoReq = '\x09' 31 | EchoRep = '\x0a' 32 | MTU = '\x01\x04' 33 | MAGIC = '\x05\x06' 34 | Challenge = '\x01' 35 | Response = '\x02' 36 | Success = '\x03' 37 | Reject = '\x04' 38 | Address = '\x03\x06' 39 | lastpkt = IP() 40 | 41 | def word(value): 42 | # Generates a two byte representation of the provided number 43 | return(chr((value/256)%256)+chr(value%256)) 44 | 45 | def TLV(type, value): 46 | # Generates a TLV for a variable length string 47 | return(type+word(len(value))+value) 48 | 49 | def confreq(payload): 50 | # Generates a TLV for a variable length string 51 | return(ConfReq + '\x01' + word(len(payload)+4) + payload) 52 | 53 | def parseconfreq(payload): 54 | # Returns a tuple containing the IP address plus any additional junk from a ConfReq 55 | ip = '' 56 | other = '' 57 | if(len(payload) > 4 and payload[0:1] == ConfReq): 58 | i = 4; 59 | while(i < len(payload) and i < ord(payload[3:4])+(256 * ord(payload[2:3]))): 60 | type = payload[i:i+1] 61 | length = payload[i+1:i+2] 62 | value = payload[i+2:i+ord(length)] 63 | if(type + length == Address): 64 | ip = value 65 | else: 66 | other += type+length+value 67 | i = i + ord(length) 68 | return([ip, other]) 69 | 70 | class PPPoESession(Automaton): 71 | # A class providing a PPPoE and PPP state machine 72 | randomcookie = False 73 | retries = 100 74 | iface="eth1" 75 | mac="00:60:6e:00:00:42" 76 | hu="\x7a\x0e\x00\x00" 77 | ac_cookie="" 78 | ac_mac="ff:ff:ff:ff:ff:ff" 79 | our_magic="\x01\x23\x45\x67" 80 | their_magic="\x00\x00\x00\x00" 81 | sess_id = 0 82 | servicename = "" 83 | username = "" 84 | password = "" 85 | chal_id = "" 86 | challenge = "" 87 | ipaddress = chr(0) + chr(0) + chr(0) + chr(0) 88 | gwipaddress = '' 89 | recvbuff = [] 90 | maxrecv = 1000 91 | 92 | # Method to check whether packets are queued 93 | def recv_queuelen(self): 94 | return(len(self.recvbuff)) 95 | 96 | # Method to get the first packet in the receive queue 97 | def recv_packet(self): 98 | if(len(self.recvbuff) > 0): 99 | return(self.recvbuff.pop()) 100 | else: 101 | return(None) 102 | # Method to send an IP packet through the PPP session 103 | def send_packet(self,payload): 104 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPv4)/payload, iface=self.iface, verbose=False) 105 | 106 | def ip(self): 107 | # Method to find the current IP address 108 | return(str(ord(self.ipaddress[0:1]))+"."+str(ord(self.ipaddress[1:2]))+"."+str(ord(self.ipaddress[2:3]))+"."+str(ord(self.ipaddress[3:4]))) 109 | 110 | def gw(self): 111 | # Method to find the current IP address 112 | return(str(ord(self.gwipaddress[0:1]))+"."+str(ord(self.gwipaddress[1:2]))+"."+str(ord(self.gwipaddress[2:3]))+"."+str(ord(self.gwipaddress[3:4]))) 113 | 114 | def getcookie(self, payload): 115 | # Method to recover an AC-Cookie from PPPoE tags 116 | loc = 0 117 | while(loc < len(payload)): 118 | att_type = payload[loc:loc+2] 119 | att_len = (256 * ord(payload[loc+2:loc+3])) + ord(payload[loc+3:loc+4]) 120 | if att_type == "\x01\x04": 121 | self.ac_cookie = payload[loc+4:loc+4+att_len] 122 | break 123 | loc = loc + att_len + 4 124 | 125 | def master_filter(self, pkt): 126 | # Filter out anything that's not PPPoE as our automaton won't be interested 127 | return (PPPoED in pkt or PPPoE in pkt) 128 | 129 | # Define possible states 130 | @ATMT.state(initial=1) 131 | def START(self): 132 | pass 133 | @ATMT.state() 134 | def WAIT_PADO(self): 135 | pass 136 | @ATMT.state() 137 | def GOT_PADO(self): 138 | pass 139 | @ATMT.state() 140 | def WAIT_PADS(self): 141 | pass 142 | @ATMT.state() 143 | def START_LCP(self): 144 | pass 145 | @ATMT.state() 146 | def LCP_Request_Sent(self): 147 | pass 148 | @ATMT.state() 149 | def LCP_Ack_Received(self): 150 | pass 151 | @ATMT.state() 152 | def LCP_Ack_Sent(self): 153 | pass 154 | @ATMT.state() 155 | def LCP_OPEN(self): 156 | pass 157 | @ATMT.state() 158 | def AUTHENTICATING(self): 159 | pass 160 | @ATMT.state() 161 | def WAIT_AUTH_RESPONSE(self): 162 | pass 163 | @ATMT.state() 164 | def START_IPCP(self): 165 | pass 166 | @ATMT.state() 167 | def IPCP_Request_Sent(self): 168 | pass 169 | @ATMT.state() 170 | def IPCP_Ack_Received(self): 171 | pass 172 | @ATMT.state() 173 | def IPCP_BOTH_PEND(self): 174 | pass 175 | @ATMT.state() 176 | def IPCP_Ack_Sent(self): 177 | pass 178 | @ATMT.state() 179 | def IPCP_OPEN(self): 180 | pass 181 | @ATMT.state(error=1) 182 | def ERROR(self): 183 | pass 184 | @ATMT.state(final=1) 185 | def END(self): 186 | pass 187 | # Define transitions 188 | # Transitions from START 189 | @ATMT.condition(START) 190 | def send_padi(self): 191 | print "Starting PPPoED" 192 | sendp(Ether(src=self.mac, dst="ff:ff:ff:ff:ff:ff")/PPPoED()/Raw(load=TLV(Service_Name,self.servicename)+TLV(Host_Unique, self.hu)),iface=self.iface, verbose=False) 193 | raise self.WAIT_PADO() 194 | # 195 | # Transitions from WAIT_PADO 196 | @ATMT.timeout(WAIT_PADO, 3) 197 | def timeout_pado(self): 198 | print "Timed out waiting for PADO" 199 | self.retries -= 1 200 | if(self.retries < 0): 201 | print "Too many retries, aborting." 202 | raise self.ERROR() 203 | raise self.START() 204 | @ATMT.receive_condition(WAIT_PADO) 205 | def receive_pado(self,pkt): 206 | if (PPPoED in pkt) and (pkt[PPPoED].code==PADO): 207 | self.ac_mac=pkt[Ether].src 208 | self.getcookie(pkt[Raw].load) 209 | raise self.GOT_PADO() 210 | # 211 | # Transitions from GOT_PADO 212 | @ATMT.condition(GOT_PADO) 213 | def send_padr(self): 214 | if(self.randomcookie): 215 | print "Random cookie being used" 216 | self.ac_cookie=os.urandom(16) 217 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoED(code=PADR)/Raw(load=TLV(Service_Name,self.servicename)+TLV(Host_Unique, self.hu)+TLV(AC_Cookie,self.ac_cookie)),iface=self.iface, verbose=False) 218 | raise self.WAIT_PADS() 219 | # 220 | # Transitions from WAIT_PADS 221 | @ATMT.timeout(WAIT_PADS, 1) 222 | def timeout_pads(self): 223 | print "Timed out waiting for PADS" 224 | self.retries -= 1 225 | if(self.retries < 0): 226 | print "Too many retries, aborting." 227 | raise self.ERROR() 228 | raise self.GOT_PADO() 229 | @ATMT.receive_condition(WAIT_PADS) 230 | def receive_pads(self,pkt): 231 | if (PPPoED in pkt) and (pkt[PPPoED].code==PADS): 232 | self.sess_id = pkt[PPPoED].sessionid 233 | raise self.START_LCP() 234 | @ATMT.receive_condition(WAIT_PADS) 235 | def receive_padt(self,pkt): 236 | if (PPPoED in pkt) and (pkt[PPPoED].code==PADT): 237 | print "Received PADT" 238 | raise self.ERROR() 239 | # 240 | # Transitions from START_LCP 241 | @ATMT.condition(START_LCP) 242 | def lcp_send_confreq(self): 243 | print "Starting LCP" 244 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=confreq(MTU+word(1492)+MAGIC+self.our_magic)),iface=self.iface, verbose=False) 245 | raise self.LCP_Request_Sent() 246 | # 247 | # Transitions from LCP_Request_Sent 248 | @ATMT.timeout(LCP_Request_Sent, 3) 249 | def lcp_req_sent_timeout(self): 250 | print "Timed out waiting for LCP from peer" 251 | self.retries -= 1 252 | if(self.retries < 0): 253 | print "Too many retries, aborting." 254 | raise self.ERROR() 255 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=confreq(MTU+word(1492)+MAGIC+self.our_magic)),iface=self.iface, verbose=False) 256 | raise self.LCP_Request_Sent() 257 | @ATMT.receive_condition(LCP_Request_Sent, prio=1) 258 | def lcp_req_sent_rx_confreq(self,pkt): 259 | # We received a ConfReq from the peer. Nak is not implemented, we just Ack anything we are sent. 260 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==ConfReq and pkt[Ether].src==self.ac_mac): 261 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=ConfAck+pkt[Raw].load[1:]),iface=self.iface, verbose=False) 262 | raise self.LCP_Ack_Sent() 263 | @ATMT.receive_condition(LCP_Request_Sent, prio=2) 264 | def lcp_req_sent_rx_confack(self,pkt): 265 | # We received a ConfAck from the peer. Now we must wait for their ConfReq. 266 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==ConfAck and pkt[Ether].src==self.ac_mac): 267 | raise self.LCP_Ack_Received() 268 | @ATMT.receive_condition(LCP_Request_Sent, prio=3) 269 | def lcp_req_sent_rx_confnakrej(self,pkt): 270 | # We received a ConfNak or a ConfRej from the peer. In theory we could negotiate but we have no parameters to fall back on so just error. 271 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==ConfNak or pkt[Raw].load[0:1]==ConfRej) and pkt[Ether].src==self.ac_mac: 272 | raise self.ERROR() 273 | # 274 | ## Transitions from LCP_Ack_Sent 275 | @ATMT.timeout(LCP_Ack_Sent, 3) 276 | def lcp_ack_sent_timeout(self): 277 | print "Timed out waiting for LCP from peer" 278 | self.retries -= 1 279 | if(self.retries < 0): 280 | print "Too many retries, aborting." 281 | raise self.ERROR() 282 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=confreq(MTU+word(1492)+MAGIC+self.our_magic)),iface=self.iface, verbose=False) 283 | raise self.LCP_Ack_Sent() 284 | @ATMT.receive_condition(LCP_Ack_Sent, prio=1) 285 | def lcp_ack_sent_rx_confack(self, pkt): 286 | # We received a ConfAck from the peer, so we are ready to play. 287 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==ConfAck and pkt[Ether].src==self.ac_mac): 288 | raise self.LCP_OPEN() 289 | @ATMT.receive_condition(LCP_Ack_Sent, prio=2) 290 | def lcp_ack_sent_rx_confreq(self,pkt): 291 | # We received a ConfReq from the peer. Nak is not implemented, we just Ack anything we are sent. 292 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==ConfReq and pkt[Ether].src==self.ac_mac): 293 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=ConfAck+pkt[Raw].load[1:]),iface=self.iface, verbose=False) 294 | raise self.LCP_Ack_Sent() 295 | @ATMT.receive_condition(LCP_Ack_Sent, prio=3) 296 | def lcp_ack_sent_rx_confnakrej(self,pkt): 297 | # We received a ConfNak or a ConfRej from the peer. In theory we could negotiate but we have no parameters to fall back on so just error. 298 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==ConfNak or pkt[Raw].load[0:1]==ConfRej) and pkt[Ether].src==self.ac_mac: 299 | raise self.ERROR() 300 | # 301 | # Transitions from LCP_Ack_Received 302 | @ATMT.timeout(LCP_Ack_Received, 3) 303 | def lcp_ack_recv_timeout(self): 304 | print "Timed out waiting for LCP from peer" 305 | self.retries -= 1 306 | if(self.retries < 0): 307 | print "Too many retries, aborting." 308 | raise self.ERROR() 309 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=confreq(MTU+word(1492)+MAGIC+self.our_magic)),iface=self.iface, verbose=False) 310 | raise self.LCP_Req_Sent() 311 | @ATMT.receive_condition(LCP_Ack_Received) 312 | def lcp_ack_recv_rx_confreq(self, pkt): 313 | # We received a ConfReq from the peer. Nak is not implemented, we just Ack anything we are sent. 314 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==ConfReq and pkt[Ether].src==self.ac_mac): 315 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=ConfAck+pkt[Raw].load[1:]),iface=self.iface, verbose=False) 316 | raise self.LCP_OPEN() 317 | # 318 | # Transitions from LCP_OPEN 319 | @ATMT.timeout(LCP_OPEN, 3) 320 | def auth_or_ipcp_timeout(self): 321 | print "Timed out waiting for authentication challenge or IPCP from peer" 322 | self.retries -= 1 323 | if(self.retries < 0): 324 | print "Too many retries, aborting." 325 | raise self.ERROR() 326 | raise self.LCP_OPEN() 327 | @ATMT.receive_condition(LCP_OPEN, prio=1) 328 | def get_challenge(self,pkt): 329 | # We received a CHAP challenge from the peer so we must authenticate ourself. 330 | if (PPP in pkt) and pkt[PPP].proto == CHAP and (pkt[Raw].load[0:1]==Challenge and pkt[Ether].src==self.ac_mac): 331 | print "Got CHAP Challenge, Authenticating" 332 | self.chal_id = pkt[Raw].load[1:2] 333 | chal_len = ord(pkt[Raw].load[4:5]) 334 | self.challenge = pkt[Raw].load[5:5+chal_len] 335 | raise self.AUTHENTICATING() 336 | @ATMT.receive_condition(LCP_OPEN, prio=2) 337 | def lcp_open_get_IPCP(self,pkt): 338 | # Straight to IPCP if the peer doesn't challenge. 339 | if (PPP in pkt) and pkt[PPP].proto == IPCP and (pkt[Raw].load[0:1]==Challenge and pkt[Ether].src==self.ac_mac): 340 | print "Got IPCP - skipping authentication" 341 | raise self.START_IPCP() 342 | # 343 | ## Transitions from AUTHENTICATING 344 | @ATMT.condition(AUTHENTICATING) 345 | def send_response(self): 346 | auth_hash = md5.new(self.chal_id + self.password + self.challenge).digest() 347 | resp_len = word(len(auth_hash + self.username)+5) 348 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=CHAP)/Raw(load=Response + self.chal_id + resp_len + '\x10' + auth_hash + self.username), iface=self.iface, verbose=False) 349 | raise self.WAIT_AUTH_RESPONSE() 350 | # 351 | ## Transitions from WAIT_AUTH_RESPONSE 352 | @ATMT.timeout(WAIT_AUTH_RESPONSE, 3) 353 | def wait_auth_response_timeout(self): 354 | # We timed out waiting for an auth response. Re-send. 355 | auth_hash = md5.new(self.chal_id + self.password + self.challenge).digest() 356 | resp_len = word(len(auth_hash + self.username)+5) 357 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=CHAP)/Raw(load=Response + self.chal_id + resp_len + '\x10' + auth_hash + self.username), iface=self.iface, verbose=False) 358 | raise self.WAIT_AUTH_RESPONSE() 359 | @ATMT.receive_condition(WAIT_AUTH_RESPONSE, prio=1) 360 | def wait_auth_response_rx_success(self,pkt): 361 | # We received a CHAP success so we can start IPCP. 362 | if (PPP in pkt) and pkt[PPP].proto == CHAP and (pkt[Raw].load[0:1]==Success and pkt[Ether].src==self.ac_mac): 363 | print "Authenticated OK" 364 | raise self.START_IPCP() 365 | @ATMT.receive_condition(WAIT_AUTH_RESPONSE, prio=2) 366 | def wait_auth_response_rx_reject(self,pkt): 367 | # We received a CHAP reject and must terminate. 368 | if (PPP in pkt) and pkt[PPP].proto == CHAP and (pkt[Raw].load[0:1]==Reject and pkt[Ether].src==self.ac_mac): 369 | print "Authentication failed, reason: " + pkt[Raw].load[4:] 370 | raise self.ERROR() 371 | @ATMT.receive_condition(WAIT_AUTH_RESPONSE, prio=3) 372 | def wait_auth_response_rx_echo(self,pkt): 373 | # Authentication can take a while so we should reply to echoes while we wait. 374 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==EchoReq and pkt[Ether].src==self.ac_mac): 375 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=EchoRep + pkt[Raw].load[1:2] + word(8) + self.our_magic), iface=self.iface, verbose=False) 376 | raise self.WAIT_AUTH_RESPONSE() 377 | @ATMT.receive_condition(WAIT_AUTH_RESPONSE, prio=4) 378 | def wait_auth_response_rx_challenge(self,pkt): 379 | # We received a CHAP challenge from the peer so we must authenticate ourself. 380 | if (PPP in pkt) and pkt[PPP].proto == CHAP and (pkt[Raw].load[0:1]==Challenge and pkt[Ether].src==self.ac_mac): 381 | self.chal_id = pkt[Raw].load[1:2] 382 | chal_len = ord(pkt[Raw].load[4:5]) 383 | self.challenge = pkt[Raw].load[5:5+chal_len] 384 | raise self.AUTHENTICATING() 385 | # 386 | ## Transitions from START_IPCP 387 | @ATMT.condition(START_IPCP) 388 | def start_ipcp_tx_confreq(self): 389 | print "Starting IPCP" 390 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=confreq(Address+self.ipaddress)), iface=self.iface, verbose=False) 391 | raise self.IPCP_Request_Sent() 392 | # 393 | ## Transitions from IPCP_Request_Sent 394 | @ATMT.timeout(IPCP_Request_Sent, 3) 395 | def ipcp_req_sent_timeout(self): 396 | # We timed out. Re-send Configure-Request. 397 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=confreq(Address+self.ipaddress)), iface=self.iface, verbose=False) 398 | raise self.IPCP_Request_Sent() 399 | @ATMT.receive_condition(IPCP_Request_Sent, prio=1) 400 | def ipcp_req_sent_rx_confack(self,pkt): 401 | # We received a ConfAck and can proceed with the current parameters. 402 | if (PPP in pkt) and pkt[PPP].proto == IPCP and (pkt[PPP].do_build_payload()[0:1]==ConfAck and pkt[Ether].src==self.ac_mac): 403 | raise self.IPCP_Ack_Received() 404 | @ATMT.receive_condition(IPCP_Request_Sent, prio=2) 405 | def ipcp_req_sent_rx_confnak(self,pkt): 406 | # We received a ConfNak and must adjust the current parameters. 407 | if (PPP in pkt) and pkt[PPP].proto == IPCP and (pkt[PPP].do_build_payload()[0:1]==ConfNak and pkt[Ether].src==self.ac_mac): 408 | suggestion = pkt[PPP].do_build_payload()[6:10] 409 | print "Peer provided our IP as " + str(ord(suggestion[0:1])) + "." + str(ord(suggestion[1:2])) + "." + str(ord(suggestion[2:3])) + "." + str(ord(suggestion[3:4])) 410 | self.ipaddress = suggestion 411 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=confreq(Address+self.ipaddress)), iface=self.iface, verbose=False) 412 | raise self.IPCP_Request_Sent() 413 | @ATMT.receive_condition(IPCP_Request_Sent, prio=3) 414 | def ipcp_req_sent_rx_confreq(self,pkt): 415 | # We received a ConfReq and must validate our peer's proposed parameters. 416 | if (PPP in pkt) and pkt[PPP].proto == IPCP and (pkt[PPP].do_build_payload()[0:1]==ConfReq and pkt[Ether].src==self.ac_mac): 417 | payload = pkt[PPP].do_build_payload() 418 | [gwip, otherstuff] = parseconfreq(payload) 419 | if(len(gwip) == 4 and otherstuff == ''): 420 | # If the other end just wants to negotiate its IP, we will take it. 421 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=ConfAck+payload[1:]), iface=self.iface, verbose=False) 422 | self.gwipaddress = gwip 423 | raise self.IPCP_Ack_Sent() 424 | else: 425 | # Otherwise we ConfRej the other parameters as they are not supported. 426 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=ConfRej+payload[1:2]+word(len(otherstuff)+4)+otherstuff), iface=self.iface, verbose=False) 427 | self.retries -= 1 428 | if(self.retries < 0): 429 | raise self.ERROR() 430 | else: 431 | raise self.IPCP_Request_Sent() 432 | @ATMT.receive_condition(IPCP_Request_Sent, prio=4) 433 | def ipcp_req_sent_rx_echo(self,pkt): 434 | # We received an LCP echo and need to reply. 435 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==EchoReq and pkt[Ether].src==self.ac_mac): 436 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=EchoRep + pkt[Raw].load[1:2] + word(8) + self.our_magic), iface=self.iface, verbose=False) 437 | raise self.IPCP_Request_Sent() 438 | # 439 | ## Transitions from IPCP_Ack_Received 440 | @ATMT.timeout(IPCP_Ack_Received, 3) 441 | def ipcp_ack_recv_timeout(self): 442 | # We timed out. Re-send Configure-Request. 443 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=confreq(Address+self.ipaddress)), iface=self.iface, verbose=False) 444 | raise self.IPCP_Request_Sent() 445 | @ATMT.receive_condition(IPCP_Ack_Received) 446 | def ipcp_ack_recv_got_confreq(self,pkt): 447 | # We received a ConfReq and must validate our peer's proposed parameters. 448 | if (PPP in pkt) and pkt[PPP].proto == IPCP and (pkt[PPP].do_build_payload()[0:1]==ConfReq and pkt[Ether].src==self.ac_mac): 449 | payload = pkt[PPP].do_build_payload() 450 | [gwip, otherstuff] = parseconfreq(payload) 451 | if(len(gwip) == 4 and otherstuff == ''): 452 | # If the other end just wants to negotiate its IP, we will take it. 453 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=ConfAck+payload[1:]), iface=self.iface, verbose=False) 454 | self.gwipaddress = gwip 455 | print "IPCP is OPEN" 456 | raise self.IPCP_OPEN() 457 | else: 458 | # Otherwise we ConfRej the other parameters as they are not supported. 459 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=ConfRej+payload[1:2]+word(len(otherstuff)+4)+otherstuff), iface=self.iface, verbose=False) 460 | self.retries -= 1 461 | if(self.retries < 0): 462 | raise self.ERROR() 463 | else: 464 | raise self.IPCP_Ack_Received() 465 | # 466 | ## Transitions from IPCP_Ack_Sent 467 | @ATMT.timeout(IPCP_Ack_Sent, 3) 468 | def ipcp_ack_sent_timeout(self): 469 | # We timed out. Re-send Configure-Request. 470 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=confreq(Address+self.ipaddress)), iface=self.iface, verbose=False) 471 | raise self.IPCP_Ack_Sent() 472 | @ATMT.receive_condition(IPCP_Ack_Sent, prio=1) 473 | def ipcp_ack_sent_rx_confack(self,pkt): 474 | # We received a ConfAck and can proceed with the current parameters. 475 | if (PPP in pkt) and pkt[PPP].proto == IPCP and (pkt[PPP].do_build_payload()[0:1]==ConfAck and pkt[Ether].src==self.ac_mac): 476 | print "IPCP Open." 477 | raise self.IPCP_OPEN() 478 | @ATMT.receive_condition(IPCP_Ack_Sent, prio=2) 479 | def ipcp_ack_sent_rx_confnak(self,pkt): 480 | # We received a ConfNak and must adjust the current parameters. 481 | if (PPP in pkt) and pkt[PPP].proto == IPCP and (pkt[PPP].do_build_payload()[0:1]==ConfNak and pkt[Ether].src==self.ac_mac): 482 | suggestion = pkt[PPP].do_build_payload()[6:10] 483 | print "Peer provided our IP as " + str(ord(suggestion[0:1])) + "." + str(ord(suggestion[1:2])) + "." + str(ord(suggestion[2:3])) + "." + str(ord(suggestion[3:4])) + "." 484 | self.ipaddress = suggestion 485 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=confreq(Address+self.ipaddress)), iface=self.iface, verbose=False) 486 | raise self.IPCP_Ack_Sent() 487 | @ATMT.receive_condition(IPCP_Ack_Sent, prio=3) 488 | def ipcp_ack_sent_rx_confreq(self,pkt): 489 | # We received a ConfReq and must re-validate our peer's proposed parameters. 490 | if (PPP in pkt) and pkt[PPP].proto == IPCP and (pkt[PPP].do_build_payload()[0:1]==ConfReq and pkt[Ether].src==self.ac_mac): 491 | payload = pkt[PPP].do_build_payload() 492 | [gwip, otherstuff] = parseconfreq(payload) 493 | if(len(gwip) == 4 and otherstuff == ''): 494 | # If the other end just wants to negotiate its IP, we will take it. 495 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=ConfAck+payload[1:]), iface=self.iface, verbose=False) 496 | self.gwipaddress = gwip 497 | raise self.IPCP_Ack_Sent() 498 | else: 499 | # Otherwise we ConfRej the other parameters as they are not supported. 500 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=IPCP)/Raw(load=ConfRej+payload[1:2]+word(len(otherstuff)+4)+otherstuff), iface=self.iface, verbose=False) 501 | self.retries -= 1 502 | if(self.retries < 0): 503 | raise self.ERROR() 504 | else: 505 | raise self.IPCP_Request_Sent() 506 | # 507 | ## Transitions from IPCP_OPEN 508 | @ATMT.receive_condition(IPCP_OPEN, prio=1) 509 | def ipcp_open_got_ip(self,pkt): 510 | # An IP packet came in. 511 | if (PPP in pkt) and pkt[PPP].proto == IPv4 and pkt[Ether].src==self.ac_mac and len(self.recvbuff) < self.maxrecv: 512 | self.recvbuff.insert(0,pkt[IP]) 513 | raise self.IPCP_OPEN() 514 | @ATMT.receive_condition(IPCP_OPEN, prio=2) 515 | def ipcp_open_got_echo(self,pkt): 516 | # Automatically respond to LCP echo requests. 517 | if (PPP in pkt) and pkt[PPP].proto == LCP and (pkt[Raw].load[0:1]==EchoReq and pkt[Ether].src==self.ac_mac): 518 | sendp(Ether(src=self.mac, dst=self.ac_mac)/PPPoE(sessionid=self.sess_id)/PPP(proto=LCP)/Raw(load=EchoRep + pkt[Raw].load[1:2] + word(8) + self.our_magic), iface=self.iface, verbose=False) 519 | raise self.IPCP_OPEN() 520 | @ATMT.receive_condition(IPCP_OPEN, prio=3) 521 | def ipcp_open_got_padt(self,pkt): 522 | # Shut down upon receipt of PADT. 523 | if (PPPoED in pkt) and (pkt[PPPoED].code==PADT): 524 | print "Received PADT, shutting down." 525 | raise self.ERROR() 526 | 527 | 528 | 529 | --------------------------------------------------------------------------------