blob: 8dc7e7b4a78691f99b737ef7af7ece63b90da04f [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"
25 "gerrit.opencord.org/voltha-bbsim/common/logger"
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090026 "github.com/google/gopacket"
27 "github.com/google/gopacket/layers"
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090028 "net"
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090029 "sync"
30)
31
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090032type clientState int
33
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090034const (
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090035 EAP_START clientState = iota + 1 //TODO: This state definition should support 802.1X
36 EAP_RESPID
37 EAP_RESPCHA
38 EAP_SUCCESS
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090039)
40
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090041type eapResponder struct {
42 clients map[clientKey]*eapClientInstance
43 eapolIn chan *byteMsg
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090044}
45
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090046type clientInstance interface {
47 transitState(cur clientState, recvbytes []byte) (next clientState, sendbytes []byte, err error)
48 getState() clientState
49 getKey() clientKey
50}
51
52type eapClientInstance struct {
53 key clientKey
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090054 srcaddr *net.HardwareAddr
55 version uint8
56 curId uint8
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090057 curState clientState
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090058}
59
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090060type clientKey struct {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090061 intfid uint32
62 onuid uint32
63}
64
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090065var resp *eapResponder
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090066var once sync.Once
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090067
68func getEAPResponder() *eapResponder {
69 once.Do(func() {
70 resp = &eapResponder{clients: make(map[clientKey]*eapClientInstance), eapolIn: nil}
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090071 })
72 return resp
73}
74
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090075func RunEapolResponder(ctx context.Context, eapolOut chan *byteMsg, eapolIn chan *byteMsg, errch chan error) {
76 responder := getEAPResponder()
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090077 responder.eapolIn = eapolIn
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090078
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090079 go func() {
80 logger.Debug("EAPOL response process starts")
81 defer logger.Debug("EAPOL response process was done")
82 for {
83 select {
84 case msg := <- eapolOut:
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090085 logger.Debug("Received eapol from eapolOut intfid:%d onuid:%d", msg.IntfId, msg.OnuId)
86 responder := getEAPResponder()
87 clients := responder.clients
88 if c, ok := clients[clientKey{intfid: msg.IntfId, onuid: msg.OnuId}]; ok {
89 logger.Debug("Got client intfid:%d onuid: %d", c.key.intfid, c.key.onuid)
90 nextstate := respondMessage("EAPOL", *c, msg, eapolIn)
91 c.updateState(nextstate)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090092 } else {
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090093 logger.Error("Failed to find eapol client instance intfid:%d onuid:%d", msg.IntfId, msg.OnuId)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090094 }
95 case <-ctx.Done():
96 return
97 }
98 }
99 }()
100}
101
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900102func respondMessage(msgtype string, client clientInstance, recvmsg *byteMsg, msgInCh chan *byteMsg) clientState {
103 curstate := client.getState()
104 nextstate, sendbytes, err := client.transitState(curstate, recvmsg.Byte)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900105
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900106 if err != nil {
107 msg := fmt.Sprintf("Failed to transitState in %s: %s", msgtype, err)
108 logger.Error(msg, err)
109 }
110
111 if sendbytes != nil {
112 key := client.getKey()
113 if err := sendBytes(key, sendbytes, msgInCh); err != nil {
114 msg := fmt.Sprintf("Failed to sendBytes in %s: %s", msgtype, err)
115 logger.Error(msg)
116 }
117 } else {
118 logger.Debug("sendbytes is nil")
119 }
120 return nextstate
121}
122
123func startEAPClient(intfid uint32, onuid uint32) error {
124 client := eapClientInstance{key: clientKey{intfid: intfid, onuid: onuid},
125 srcaddr: &net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, 0x07, byte(onuid)},
126 version: 1,
127 curId: 0,
128 curState: EAP_START}
129
130 eap := client.createEAPStart()
131 bytes := client.createEAPOL(eap)
132 resp := getEAPResponder()
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900133 eapolIn := resp.eapolIn
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900134 if err := sendBytes(clientKey{intfid, onuid}, bytes, eapolIn); err != nil {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900135 return errors.New("Failed to send EAPStart")
136 }
137 logger.Debug("Sending EAPStart")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900138 //clients[key{intfid: intfid, onuid: onuid}] = &client
139 resp.clients[clientKey{intfid: intfid, onuid: onuid}] = &client
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900140 return nil
141}
142
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900143func (c eapClientInstance) transitState(cur clientState, recvbytes []byte) (next clientState, respbytes []byte, err error) {
144 recvpkt := gopacket.NewPacket(recvbytes, layers.LayerTypeEthernet, gopacket.Default)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900145 eap, err := extractEAP(recvpkt)
146 if err != nil {
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900147 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900148 }
149 if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
150 logger.Debug("Received EAP-Request/Identity")
151 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900152 c.curId = eap.Id
153 if cur == EAP_START {
154 reseap := c.createEAPResID()
155 pkt := c.createEAPOL(reseap)
156 return EAP_RESPID, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900157 }
158 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
159 logger.Debug("Received EAP-Request/Challenge")
160 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900161 if cur == EAP_RESPID {
162 c.curId = eap.Id
163 senddata := getMD5Data(c.curId, eap)
164 senddata = append([]byte{0x10}, senddata...)
165 sendeap := c.createEAPResCha(senddata)
166 pkt := c.createEAPOL(sendeap)
167 return EAP_RESPCHA, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900168 }
169 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
170 logger.Debug("Received EAP-Success")
171 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900172 if cur == EAP_RESPCHA {
173 return EAP_SUCCESS, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900174 }
175 } else {
176 logger.Debug("Received unsupported EAP")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900177 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900178 }
179 logger.Debug("State transition does not support..current state:%d", cur)
180 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900181 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900182}
183
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900184func (c eapClientInstance) getState() clientState {
185 return c.curState
186}
187
188func (c *eapClientInstance) updateState(state clientState) {
189 msg := fmt.Sprintf("EAP update state intfid:%d onuid:%d state:%d", c.key.intfid, c.key.onuid, state)
190 logger.Debug(msg)
191 c.curState = state
192}
193
194func (c eapClientInstance) getKey() clientKey {
195 return c.key
196}
197
198func sendBytes(key clientKey, pkt []byte, chIn chan *byteMsg) error {
199 // Send our packet
200 msg := byteMsg{IntfId: key.intfid,
201 OnuId: key.onuid,
202 Byte: pkt}
203 chIn <- &msg
204 logger.Debug("sendBytes intfid:%d onuid:%d", key.intfid, key.onuid)
205 logger.Debug(hex.Dump(msg.Byte))
206 return nil
207}
208
209func (c *eapClientInstance) createEAPOL(eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900210 buffer := gopacket.NewSerializeBuffer()
211 options := gopacket.SerializeOptions{}
212
213 ethernetLayer := &layers.Ethernet{
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900214 SrcMAC: *c.srcaddr,
215 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900216 EthernetType: layers.EthernetTypeEAPOL,
217 }
218
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900219 if eap == nil { // EAP Start
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900220 gopacket.SerializeLayers(buffer, options,
221 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900222 &layers.EAPOL{Version: c.version, Type: 1, Length: 0},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900223 )
224 } else {
225 gopacket.SerializeLayers(buffer, options,
226 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900227 &layers.EAPOL{Version: c.version, Type: 0, Length: eap.Length},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900228 eap,
229 )
230 }
231 bytes := buffer.Bytes()
232 return bytes
233}
234
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900235func (c *eapClientInstance) createEAPStart() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900236 return nil
237}
238
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900239func (c *eapClientInstance) createEAPResID() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900240 eap := layers.EAP{Code: layers.EAPCodeResponse,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900241 Id: c.curId,
242 Length: 9,
243 Type: layers.EAPTypeIdentity,
244 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900245 return &eap
246}
247
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900248func (c *eapClientInstance) createEAPResCha(payload []byte) *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900249 eap := layers.EAP{Code: layers.EAPCodeResponse,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900250 Id: c.curId, Length: 22,
251 Type: layers.EAPTypeOTP,
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900252 TypeData: payload}
253 return &eap
254}
255
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900256func getMD5Data (id uint8, eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900257 i := byte(id)
258 C := []byte(eap.BaseLayer.Contents)[6:]
259 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} //"password"
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900260 data := md5.Sum(append(P, C...))
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900261 ret := make([]byte, 16)
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900262 for j := 0; j < 16; j++ {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900263 ret[j] = data[j]
264 }
265 return ret
266}
267
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900268func extractEAPOL(pkt gopacket.Packet) (*layers.EAPOL, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900269 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
270 eapol, _ := layerEAPOL.(*layers.EAPOL)
271 if eapol == nil {
272 return nil, errors.New("Cannot extract EAPOL")
273 }
274 return eapol, nil
275}
276
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900277func extractEAP(pkt gopacket.Packet) (*layers.EAP, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900278 layerEAP := pkt.Layer(layers.LayerTypeEAP)
279 eap, _ := layerEAP.(*layers.EAP)
280 if eap == nil {
281 return nil, errors.New("Cannot extract EAP")
282 }
283 return eap, nil
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900284}