blob: cc9f24c520d36dd3e8a1d8d81287223f5ae55eec [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"
27
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090028 "gerrit.opencord.org/voltha-bbsim/common/logger"
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090029 "github.com/google/gopacket"
30 "github.com/google/gopacket/layers"
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090031)
32
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090033type clientState int
34
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020035// Constants for eapol states
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090036const (
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020037 EAP_START clientState = iota + 1 // TODO: This state definition should support 802.1X
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090038 EAP_RESPID
39 EAP_RESPCHA
40 EAP_SUCCESS
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090041)
42
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090043type eapResponder struct {
44 clients map[clientKey]*eapClientInstance
45 eapolIn chan *byteMsg
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090046}
47
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090048type clientInstance interface {
49 transitState(cur clientState, recvbytes []byte) (next clientState, sendbytes []byte, err error)
50 getState() clientState
51 getKey() clientKey
52}
53
54type eapClientInstance struct {
55 key clientKey
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090056 srcaddr *net.HardwareAddr
57 version uint8
58 curId uint8
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090059 curState clientState
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090060}
61
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090062type clientKey struct {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090063 intfid uint32
64 onuid uint32
65}
66
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090067var resp *eapResponder
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090068var once sync.Once
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090069
70func getEAPResponder() *eapResponder {
71 once.Do(func() {
72 resp = &eapResponder{clients: make(map[clientKey]*eapClientInstance), eapolIn: nil}
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090073 })
74 return resp
75}
76
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020077// RunEapolResponder starts go routine which processes and responds for received eapol messages
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090078func RunEapolResponder(ctx context.Context, eapolOut chan *byteMsg, eapolIn chan *byteMsg, errch chan error) {
79 responder := getEAPResponder()
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090080 responder.eapolIn = eapolIn
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090081
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090082 go func() {
83 logger.Debug("EAPOL response process starts")
84 defer logger.Debug("EAPOL response process was done")
85 for {
86 select {
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020087 case msg := <-eapolOut:
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090088 logger.Debug("Received eapol from eapolOut intfid:%d onuid:%d", msg.IntfId, msg.OnuId)
89 responder := getEAPResponder()
90 clients := responder.clients
91 if c, ok := clients[clientKey{intfid: msg.IntfId, onuid: msg.OnuId}]; ok {
92 logger.Debug("Got client intfid:%d onuid: %d", c.key.intfid, c.key.onuid)
93 nextstate := respondMessage("EAPOL", *c, msg, eapolIn)
94 c.updateState(nextstate)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090095 } else {
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090096 logger.Error("Failed to find eapol client instance intfid:%d onuid:%d", msg.IntfId, msg.OnuId)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090097 }
98 case <-ctx.Done():
99 return
100 }
101 }
102 }()
103}
104
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900105func respondMessage(msgtype string, client clientInstance, recvmsg *byteMsg, msgInCh chan *byteMsg) clientState {
106 curstate := client.getState()
107 nextstate, sendbytes, err := client.transitState(curstate, recvmsg.Byte)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900108
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900109 if err != nil {
110 msg := fmt.Sprintf("Failed to transitState in %s: %s", msgtype, err)
111 logger.Error(msg, err)
112 }
113
114 if sendbytes != nil {
115 key := client.getKey()
116 if err := sendBytes(key, sendbytes, msgInCh); err != nil {
117 msg := fmt.Sprintf("Failed to sendBytes in %s: %s", msgtype, err)
118 logger.Error(msg)
119 }
120 } else {
121 logger.Debug("sendbytes is nil")
122 }
123 return nextstate
124}
125
126func startEAPClient(intfid uint32, onuid uint32) error {
127 client := eapClientInstance{key: clientKey{intfid: intfid, onuid: onuid},
128 srcaddr: &net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, 0x07, byte(onuid)},
129 version: 1,
130 curId: 0,
131 curState: EAP_START}
132
133 eap := client.createEAPStart()
134 bytes := client.createEAPOL(eap)
135 resp := getEAPResponder()
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900136 eapolIn := resp.eapolIn
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900137 if err := sendBytes(clientKey{intfid, onuid}, bytes, eapolIn); err != nil {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900138 return errors.New("Failed to send EAPStart")
139 }
140 logger.Debug("Sending EAPStart")
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200141 // clients[key{intfid: intfid, onuid: onuid}] = &client
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900142 resp.clients[clientKey{intfid: intfid, onuid: onuid}] = &client
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900143 return nil
144}
145
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900146func (c eapClientInstance) transitState(cur clientState, recvbytes []byte) (next clientState, respbytes []byte, err error) {
147 recvpkt := gopacket.NewPacket(recvbytes, layers.LayerTypeEthernet, gopacket.Default)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900148 eap, err := extractEAP(recvpkt)
149 if err != nil {
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900150 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900151 }
152 if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
153 logger.Debug("Received EAP-Request/Identity")
154 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900155 c.curId = eap.Id
156 if cur == EAP_START {
157 reseap := c.createEAPResID()
158 pkt := c.createEAPOL(reseap)
159 return EAP_RESPID, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900160 }
161 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
162 logger.Debug("Received EAP-Request/Challenge")
163 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900164 if cur == EAP_RESPID {
165 c.curId = eap.Id
166 senddata := getMD5Data(c.curId, eap)
167 senddata = append([]byte{0x10}, senddata...)
168 sendeap := c.createEAPResCha(senddata)
169 pkt := c.createEAPOL(sendeap)
170 return EAP_RESPCHA, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900171 }
172 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
173 logger.Debug("Received EAP-Success")
174 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900175 if cur == EAP_RESPCHA {
176 return EAP_SUCCESS, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900177 }
178 } else {
179 logger.Debug("Received unsupported EAP")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900180 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900181 }
182 logger.Debug("State transition does not support..current state:%d", cur)
183 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900184 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900185}
186
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900187func (c eapClientInstance) getState() clientState {
188 return c.curState
189}
190
191func (c *eapClientInstance) updateState(state clientState) {
192 msg := fmt.Sprintf("EAP update state intfid:%d onuid:%d state:%d", c.key.intfid, c.key.onuid, state)
193 logger.Debug(msg)
194 c.curState = state
195}
196
197func (c eapClientInstance) getKey() clientKey {
198 return c.key
199}
200
201func sendBytes(key clientKey, pkt []byte, chIn chan *byteMsg) error {
202 // Send our packet
203 msg := byteMsg{IntfId: key.intfid,
204 OnuId: key.onuid,
205 Byte: pkt}
206 chIn <- &msg
207 logger.Debug("sendBytes intfid:%d onuid:%d", key.intfid, key.onuid)
208 logger.Debug(hex.Dump(msg.Byte))
209 return nil
210}
211
212func (c *eapClientInstance) createEAPOL(eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900213 buffer := gopacket.NewSerializeBuffer()
214 options := gopacket.SerializeOptions{}
215
216 ethernetLayer := &layers.Ethernet{
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900217 SrcMAC: *c.srcaddr,
218 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900219 EthernetType: layers.EthernetTypeEAPOL,
220 }
221
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900222 if eap == nil { // EAP Start
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900223 gopacket.SerializeLayers(buffer, options,
224 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900225 &layers.EAPOL{Version: c.version, Type: 1, Length: 0},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900226 )
227 } else {
228 gopacket.SerializeLayers(buffer, options,
229 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900230 &layers.EAPOL{Version: c.version, Type: 0, Length: eap.Length},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900231 eap,
232 )
233 }
234 bytes := buffer.Bytes()
235 return bytes
236}
237
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900238func (c *eapClientInstance) createEAPStart() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900239 return nil
240}
241
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900242func (c *eapClientInstance) createEAPResID() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900243 eap := layers.EAP{Code: layers.EAPCodeResponse,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900244 Id: c.curId,
245 Length: 9,
246 Type: layers.EAPTypeIdentity,
247 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900248 return &eap
249}
250
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900251func (c *eapClientInstance) createEAPResCha(payload []byte) *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900252 eap := layers.EAP{Code: layers.EAPCodeResponse,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900253 Id: c.curId, Length: 22,
254 Type: layers.EAPTypeOTP,
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900255 TypeData: payload}
256 return &eap
257}
258
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200259func getMD5Data(id uint8, eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900260 i := byte(id)
261 C := []byte(eap.BaseLayer.Contents)[6:]
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200262 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} // "password"
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900263 data := md5.Sum(append(P, C...))
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900264 ret := make([]byte, 16)
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900265 for j := 0; j < 16; j++ {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900266 ret[j] = data[j]
267 }
268 return ret
269}
270
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900271func extractEAPOL(pkt gopacket.Packet) (*layers.EAPOL, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900272 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
273 eapol, _ := layerEAPOL.(*layers.EAPOL)
274 if eapol == nil {
275 return nil, errors.New("Cannot extract EAPOL")
276 }
277 return eapol, nil
278}
279
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900280func extractEAP(pkt gopacket.Packet) (*layers.EAP, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900281 layerEAP := pkt.Layer(layers.LayerTypeEAP)
282 eap, _ := layerEAP.(*layers.EAP)
283 if eap == nil {
284 return nil, errors.New("Cannot extract EAP")
285 }
286 return eap, nil
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900287}