blob: 0300141f9334c62c6d2eb0f7aa5f612df17ddd76 [file] [log] [blame]
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +09001/*
2 * Copyright 2018-present Open Networking Foundation
3
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7
8 * http://www.apache.org/licenses/LICENSE-2.0
9
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package core
18
19import (
20 "context"
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090021 "crypto/md5"
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090022 "encoding/hex"
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090023 "errors"
24 "fmt"
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020025 "net"
26 "sync"
Matteo Scandolo67add0c2019-08-01 16:41:14 -070027 "time"
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020028
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090029 "github.com/google/gopacket"
30 "github.com/google/gopacket/layers"
Zack Williams2abf3932019-08-05 14:07:05 -070031 "github.com/opencord/voltha-bbsim/common/logger"
Zdravko Bozakov078a2712019-07-19 23:25:15 +020032 log "github.com/sirupsen/logrus"
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090033)
34
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090035type clientState int
36
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020037// Constants for eapol states
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090038const (
Zdravko Bozakov078a2712019-07-19 23:25:15 +020039 EapStart clientState = iota + 1 // TODO: This state definition should support 802.1X
40 EapRespid
41 EapRespcha
42 EapSuccess
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090043)
44
Matt Jeanneret7c9c5f22019-08-09 14:40:12 -040045func (eap clientState) String() string {
Matteo Scandolo67add0c2019-08-01 16:41:14 -070046 return [...]string{"EAP_START", "EAP_RESPID", "EAP_RESPCHA", "EAP_SUCCESS"}[eap]
47}
48
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090049type eapResponder struct {
50 clients map[clientKey]*eapClientInstance
51 eapolIn chan *byteMsg
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090052}
53
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090054type clientInstance interface {
55 transitState(cur clientState, recvbytes []byte) (next clientState, sendbytes []byte, err error)
56 getState() clientState
57 getKey() clientKey
58}
59
60type eapClientInstance struct {
61 key clientKey
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090062 srcaddr *net.HardwareAddr
63 version uint8
Zdravko Bozakov078a2712019-07-19 23:25:15 +020064 curID uint8
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090065 curState clientState
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090066}
67
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090068type clientKey struct {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090069 intfid uint32
70 onuid uint32
71}
72
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090073var resp *eapResponder
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090074var once sync.Once
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090075
76func getEAPResponder() *eapResponder {
77 once.Do(func() {
78 resp = &eapResponder{clients: make(map[clientKey]*eapClientInstance), eapolIn: nil}
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090079 })
80 return resp
81}
82
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020083// RunEapolResponder starts go routine which processes and responds for received eapol messages
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090084func RunEapolResponder(ctx context.Context, eapolOut chan *byteMsg, eapolIn chan *byteMsg, errch chan error) {
85 responder := getEAPResponder()
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090086 responder.eapolIn = eapolIn
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090087
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090088 go func() {
89 logger.Debug("EAPOL response process starts")
90 defer logger.Debug("EAPOL response process was done")
91 for {
92 select {
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020093 case msg := <-eapolOut:
Zdravko Bozakov078a2712019-07-19 23:25:15 +020094 logger.Debug("Received eapol from eapolOut intfid:%d onuid:%d", msg.IntfID, msg.OnuID)
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090095 responder := getEAPResponder()
96 clients := responder.clients
Zdravko Bozakov078a2712019-07-19 23:25:15 +020097 if c, ok := clients[clientKey{intfid: msg.IntfID, onuid: msg.OnuID}]; ok {
98 logger.Debug("Got client intfid:%d onuid: %d (ClientID: %v)", c.key.intfid, c.key.onuid, c.curID)
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090099 nextstate := respondMessage("EAPOL", *c, msg, eapolIn)
100 c.updateState(nextstate)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900101 } else {
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700102 logger.WithFields(log.Fields{
103 "clients": clients,
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200104 }).Errorf("Failed to find eapol client instance intfid:%d onuid:%d", msg.IntfID, msg.OnuID)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900105 }
106 case <-ctx.Done():
107 return
108 }
109 }
110 }()
111}
112
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900113func respondMessage(msgtype string, client clientInstance, recvmsg *byteMsg, msgInCh chan *byteMsg) clientState {
114 curstate := client.getState()
115 nextstate, sendbytes, err := client.transitState(curstate, recvmsg.Byte)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900116
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900117 if err != nil {
118 msg := fmt.Sprintf("Failed to transitState in %s: %s", msgtype, err)
119 logger.Error(msg, err)
120 }
121
122 if sendbytes != nil {
123 key := client.getKey()
124 if err := sendBytes(key, sendbytes, msgInCh); err != nil {
125 msg := fmt.Sprintf("Failed to sendBytes in %s: %s", msgtype, err)
126 logger.Error(msg)
127 }
128 } else {
129 logger.Debug("sendbytes is nil")
130 }
131 return nextstate
132}
133
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700134func sendEAPStart(intfid uint32, onuid uint32, client eapClientInstance, bytes []byte, eapolIn chan *byteMsg) error {
135 for {
136 responder := getEAPResponder()
137 clients := responder.clients
138 if c, ok := clients[clientKey{intfid: intfid, onuid: onuid}]; ok {
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200139 if c.curState == EapSuccess {
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700140 logger.WithFields(log.Fields{
141 "int_id": intfid,
142 "onu_id": onuid,
143 }).Debug("EAP_SUCCESS received, stop retrying")
144 break
145 }
A R Karthickb3f4ce92019-08-09 00:16:21 +0000146 // Reset state to EAP start
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200147 c.updateState(EapStart)
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700148 } else {
149 logger.WithFields(log.Fields{
150 "clients": clients,
151 }).Errorf("Failed to find eapol client instance intfid:%d onuid:%d (sendEAPStart)", intfid, onuid)
152 }
153 if err := sendBytes(clientKey{intfid, onuid}, bytes, eapolIn); err != nil {
154 return errors.New("Failed to send EAPStart")
155 }
156 logger.WithFields(log.Fields{
Matt Jeanneret7c9c5f22019-08-09 14:40:12 -0400157 "int_id": intfid,
158 "onu_id": onuid,
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700159 "eapolIn": eapolIn,
Matt Jeanneret7c9c5f22019-08-09 14:40:12 -0400160 "bytes": bytes,
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700161 }).Debug("EAPStart Sent")
162 time.Sleep(30 * time.Second)
163 }
164 return nil
165}
166
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900167func startEAPClient(intfid uint32, onuid uint32) error {
168 client := eapClientInstance{key: clientKey{intfid: intfid, onuid: onuid},
169 srcaddr: &net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, 0x07, byte(onuid)},
170 version: 1,
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200171 curID: 0,
172 curState: EapStart}
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900173
174 eap := client.createEAPStart()
175 bytes := client.createEAPOL(eap)
176 resp := getEAPResponder()
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900177 eapolIn := resp.eapolIn
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700178 // start a loop that keeps sending EAPOL packets until it succeeds
179 go sendEAPStart(intfid, onuid, client, bytes, eapolIn)
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200180 // clients[key{intfid: intfid, onuid: onuid}] = &client
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900181 resp.clients[clientKey{intfid: intfid, onuid: onuid}] = &client
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900182 return nil
183}
184
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900185func (c eapClientInstance) transitState(cur clientState, recvbytes []byte) (next clientState, respbytes []byte, err error) {
186 recvpkt := gopacket.NewPacket(recvbytes, layers.LayerTypeEthernet, gopacket.Default)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900187 eap, err := extractEAP(recvpkt)
188 if err != nil {
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900189 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900190 }
191 if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
192 logger.Debug("Received EAP-Request/Identity")
193 logger.Debug(recvpkt.Dump())
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200194 c.curID = eap.Id
195 if cur == EapStart {
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900196 reseap := c.createEAPResID()
197 pkt := c.createEAPOL(reseap)
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200198 logger.Debug("Moving from EapStart to EapRespid")
199 return EapRespid, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900200 }
201 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
202 logger.Debug("Received EAP-Request/Challenge")
203 logger.Debug(recvpkt.Dump())
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200204 if cur == EapRespid {
205 c.curID = eap.Id
206 senddata := getMD5Data(c.curID, eap)
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900207 senddata = append([]byte{0x10}, senddata...)
208 sendeap := c.createEAPResCha(senddata)
209 pkt := c.createEAPOL(sendeap)
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200210 logger.Debug("Moving from EapRespid to EapRespcha")
211 return EapRespcha, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900212 }
213 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
214 logger.Debug("Received EAP-Success")
215 logger.Debug(recvpkt.Dump())
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200216 if cur == EapRespcha {
217 logger.Debug("Moving from EapRespcha to EapSuccess")
218 return EapSuccess, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900219 }
220 } else {
221 logger.Debug("Received unsupported EAP")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900222 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900223 }
224 logger.Debug("State transition does not support..current state:%d", cur)
225 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900226 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900227}
228
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900229func (c eapClientInstance) getState() clientState {
230 return c.curState
231}
232
233func (c *eapClientInstance) updateState(state clientState) {
234 msg := fmt.Sprintf("EAP update state intfid:%d onuid:%d state:%d", c.key.intfid, c.key.onuid, state)
235 logger.Debug(msg)
236 c.curState = state
237}
238
239func (c eapClientInstance) getKey() clientKey {
240 return c.key
241}
242
243func sendBytes(key clientKey, pkt []byte, chIn chan *byteMsg) error {
244 // Send our packet
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200245 msg := byteMsg{IntfID: key.intfid,
246 OnuID: key.onuid,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900247 Byte: pkt}
248 chIn <- &msg
249 logger.Debug("sendBytes intfid:%d onuid:%d", key.intfid, key.onuid)
250 logger.Debug(hex.Dump(msg.Byte))
251 return nil
252}
253
254func (c *eapClientInstance) createEAPOL(eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900255 buffer := gopacket.NewSerializeBuffer()
256 options := gopacket.SerializeOptions{}
257
258 ethernetLayer := &layers.Ethernet{
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900259 SrcMAC: *c.srcaddr,
260 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900261 EthernetType: layers.EthernetTypeEAPOL,
262 }
263
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900264 if eap == nil { // EAP Start
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200265 _ = gopacket.SerializeLayers(buffer, options,
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900266 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900267 &layers.EAPOL{Version: c.version, Type: 1, Length: 0},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900268 )
269 } else {
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200270 _ = gopacket.SerializeLayers(buffer, options,
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900271 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900272 &layers.EAPOL{Version: c.version, Type: 0, Length: eap.Length},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900273 eap,
274 )
275 }
276 bytes := buffer.Bytes()
277 return bytes
278}
279
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900280func (c *eapClientInstance) createEAPStart() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900281 return nil
282}
283
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900284func (c *eapClientInstance) createEAPResID() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900285 eap := layers.EAP{Code: layers.EAPCodeResponse,
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200286 Id: c.curID,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900287 Length: 9,
288 Type: layers.EAPTypeIdentity,
289 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900290 return &eap
291}
292
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900293func (c *eapClientInstance) createEAPResCha(payload []byte) *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900294 eap := layers.EAP{Code: layers.EAPCodeResponse,
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200295 Id: c.curID, Length: 22,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900296 Type: layers.EAPTypeOTP,
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900297 TypeData: payload}
298 return &eap
299}
300
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200301func getMD5Data(id uint8, eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900302 i := byte(id)
303 C := []byte(eap.BaseLayer.Contents)[6:]
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200304 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} // "password"
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900305 data := md5.Sum(append(P, C...))
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900306 ret := make([]byte, 16)
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900307 for j := 0; j < 16; j++ {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900308 ret[j] = data[j]
309 }
310 return ret
311}
312
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900313func extractEAPOL(pkt gopacket.Packet) (*layers.EAPOL, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900314 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
315 eapol, _ := layerEAPOL.(*layers.EAPOL)
316 if eapol == nil {
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200317 return nil, errors.New("cannot extract EAPOL")
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900318 }
319 return eapol, nil
320}
321
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900322func extractEAP(pkt gopacket.Packet) (*layers.EAP, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900323 layerEAP := pkt.Layer(layers.LayerTypeEAP)
324 eap, _ := layerEAP.(*layers.EAP)
325 if eap == nil {
Zdravko Bozakov078a2712019-07-19 23:25:15 +0200326 return nil, errors.New("cannot extract EAP")
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900327 }
328 return eap, nil
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900329}