blob: c4dfe54b0f8ab45be9e2226e92857f60345b689b [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"
Matteo Scandolo67add0c2019-08-01 16:41:14 -070025 log "github.com/sirupsen/logrus"
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020026 "net"
27 "sync"
Matteo Scandolo67add0c2019-08-01 16:41:14 -070028 "time"
Zdravko Bozakov7401ff22019-05-28 22:45:12 +020029
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090030 "github.com/google/gopacket"
31 "github.com/google/gopacket/layers"
Zack Williams2abf3932019-08-05 14:07:05 -070032 "github.com/opencord/voltha-bbsim/common/logger"
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 Bozakov7401ff22019-05-28 22:45:12 +020039 EAP_START clientState = iota + 1 // TODO: This state definition should support 802.1X
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090040 EAP_RESPID
41 EAP_RESPCHA
42 EAP_SUCCESS
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090043)
44
Matteo Scandolo67add0c2019-08-01 16:41:14 -070045func (eap clientState) String() string {
46 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
64 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:
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090094 logger.Debug("Received eapol from eapolOut intfid:%d onuid:%d", msg.IntfId, msg.OnuId)
95 responder := getEAPResponder()
96 clients := responder.clients
97 if c, ok := clients[clientKey{intfid: msg.IntfId, onuid: msg.OnuId}]; ok {
Matteo Scandolo67add0c2019-08-01 16:41:14 -070098 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,
104 }).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 {
139 if c.curState == EAP_SUCCESS {
140 logger.WithFields(log.Fields{
141 "int_id": intfid,
142 "onu_id": onuid,
143 }).Debug("EAP_SUCCESS received, stop retrying")
144 break
145 }
146 } else {
147 logger.WithFields(log.Fields{
148 "clients": clients,
149 }).Errorf("Failed to find eapol client instance intfid:%d onuid:%d (sendEAPStart)", intfid, onuid)
150 }
151 if err := sendBytes(clientKey{intfid, onuid}, bytes, eapolIn); err != nil {
152 return errors.New("Failed to send EAPStart")
153 }
154 logger.WithFields(log.Fields{
155 "int_id": intfid,
156 "onu_id": onuid,
157 "eapolIn": eapolIn,
158 "bytes": bytes,
159 }).Debug("EAPStart Sent")
160 time.Sleep(30 * time.Second)
161 }
162 return nil
163}
164
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900165func startEAPClient(intfid uint32, onuid uint32) error {
166 client := eapClientInstance{key: clientKey{intfid: intfid, onuid: onuid},
167 srcaddr: &net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, 0x07, byte(onuid)},
168 version: 1,
169 curId: 0,
170 curState: EAP_START}
171
172 eap := client.createEAPStart()
173 bytes := client.createEAPOL(eap)
174 resp := getEAPResponder()
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900175 eapolIn := resp.eapolIn
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700176 // start a loop that keeps sending EAPOL packets until it succeeds
177 go sendEAPStart(intfid, onuid, client, bytes, eapolIn)
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200178 // clients[key{intfid: intfid, onuid: onuid}] = &client
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900179 resp.clients[clientKey{intfid: intfid, onuid: onuid}] = &client
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900180 return nil
181}
182
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900183func (c eapClientInstance) transitState(cur clientState, recvbytes []byte) (next clientState, respbytes []byte, err error) {
184 recvpkt := gopacket.NewPacket(recvbytes, layers.LayerTypeEthernet, gopacket.Default)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900185 eap, err := extractEAP(recvpkt)
186 if err != nil {
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900187 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900188 }
189 if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
190 logger.Debug("Received EAP-Request/Identity")
191 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900192 c.curId = eap.Id
193 if cur == EAP_START {
194 reseap := c.createEAPResID()
195 pkt := c.createEAPOL(reseap)
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700196 logger.Debug("Moving from EAP_START to EAP_RESPID")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900197 return EAP_RESPID, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900198 }
199 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
200 logger.Debug("Received EAP-Request/Challenge")
201 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900202 if cur == EAP_RESPID {
203 c.curId = eap.Id
204 senddata := getMD5Data(c.curId, eap)
205 senddata = append([]byte{0x10}, senddata...)
206 sendeap := c.createEAPResCha(senddata)
207 pkt := c.createEAPOL(sendeap)
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700208 logger.Debug("Moving from EAP_RESPID to EAP_RESPCHA")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900209 return EAP_RESPCHA, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900210 }
211 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
212 logger.Debug("Received EAP-Success")
213 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900214 if cur == EAP_RESPCHA {
Matteo Scandolo67add0c2019-08-01 16:41:14 -0700215 logger.Debug("Moving from EAP_RESPCHA to EAP_SUCCESS")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900216 return EAP_SUCCESS, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900217 }
218 } else {
219 logger.Debug("Received unsupported EAP")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900220 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900221 }
222 logger.Debug("State transition does not support..current state:%d", cur)
223 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900224 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900225}
226
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900227func (c eapClientInstance) getState() clientState {
228 return c.curState
229}
230
231func (c *eapClientInstance) updateState(state clientState) {
232 msg := fmt.Sprintf("EAP update state intfid:%d onuid:%d state:%d", c.key.intfid, c.key.onuid, state)
233 logger.Debug(msg)
234 c.curState = state
235}
236
237func (c eapClientInstance) getKey() clientKey {
238 return c.key
239}
240
241func sendBytes(key clientKey, pkt []byte, chIn chan *byteMsg) error {
242 // Send our packet
243 msg := byteMsg{IntfId: key.intfid,
244 OnuId: key.onuid,
245 Byte: pkt}
246 chIn <- &msg
247 logger.Debug("sendBytes intfid:%d onuid:%d", key.intfid, key.onuid)
248 logger.Debug(hex.Dump(msg.Byte))
249 return nil
250}
251
252func (c *eapClientInstance) createEAPOL(eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900253 buffer := gopacket.NewSerializeBuffer()
254 options := gopacket.SerializeOptions{}
255
256 ethernetLayer := &layers.Ethernet{
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900257 SrcMAC: *c.srcaddr,
258 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900259 EthernetType: layers.EthernetTypeEAPOL,
260 }
261
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900262 if eap == nil { // EAP Start
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900263 gopacket.SerializeLayers(buffer, options,
264 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900265 &layers.EAPOL{Version: c.version, Type: 1, Length: 0},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900266 )
267 } else {
268 gopacket.SerializeLayers(buffer, options,
269 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900270 &layers.EAPOL{Version: c.version, Type: 0, Length: eap.Length},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900271 eap,
272 )
273 }
274 bytes := buffer.Bytes()
275 return bytes
276}
277
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900278func (c *eapClientInstance) createEAPStart() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900279 return nil
280}
281
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900282func (c *eapClientInstance) createEAPResID() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900283 eap := layers.EAP{Code: layers.EAPCodeResponse,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900284 Id: c.curId,
285 Length: 9,
286 Type: layers.EAPTypeIdentity,
287 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900288 return &eap
289}
290
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900291func (c *eapClientInstance) createEAPResCha(payload []byte) *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900292 eap := layers.EAP{Code: layers.EAPCodeResponse,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900293 Id: c.curId, Length: 22,
294 Type: layers.EAPTypeOTP,
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900295 TypeData: payload}
296 return &eap
297}
298
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200299func getMD5Data(id uint8, eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900300 i := byte(id)
301 C := []byte(eap.BaseLayer.Contents)[6:]
Zdravko Bozakov7401ff22019-05-28 22:45:12 +0200302 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} // "password"
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900303 data := md5.Sum(append(P, C...))
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900304 ret := make([]byte, 16)
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900305 for j := 0; j < 16; j++ {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900306 ret[j] = data[j]
307 }
308 return ret
309}
310
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900311func extractEAPOL(pkt gopacket.Packet) (*layers.EAPOL, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900312 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
313 eapol, _ := layerEAPOL.(*layers.EAPOL)
314 if eapol == nil {
315 return nil, errors.New("Cannot extract EAPOL")
316 }
317 return eapol, nil
318}
319
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900320func extractEAP(pkt gopacket.Packet) (*layers.EAP, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900321 layerEAP := pkt.Layer(layers.LayerTypeEAP)
322 eap, _ := layerEAP.(*layers.EAP)
323 if eap == nil {
324 return nil, errors.New("Cannot extract EAP")
325 }
326 return eap, nil
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900327}