blob: 85a9f07cfa8c30735a073e563190b6782ec0554e [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
Zdravko Bozakov8b9328c2019-05-15 05:13:34 +020075//RunEapolResponder starts go routine which processes and responds for received eapol messages
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090076func RunEapolResponder(ctx context.Context, eapolOut chan *byteMsg, eapolIn chan *byteMsg, errch chan error) {
77 responder := getEAPResponder()
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090078 responder.eapolIn = eapolIn
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090079
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090080 go func() {
81 logger.Debug("EAPOL response process starts")
82 defer logger.Debug("EAPOL response process was done")
83 for {
84 select {
85 case msg := <- eapolOut:
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090086 logger.Debug("Received eapol from eapolOut intfid:%d onuid:%d", msg.IntfId, msg.OnuId)
87 responder := getEAPResponder()
88 clients := responder.clients
89 if c, ok := clients[clientKey{intfid: msg.IntfId, onuid: msg.OnuId}]; ok {
90 logger.Debug("Got client intfid:%d onuid: %d", c.key.intfid, c.key.onuid)
91 nextstate := respondMessage("EAPOL", *c, msg, eapolIn)
92 c.updateState(nextstate)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090093 } else {
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +090094 logger.Error("Failed to find eapol client instance intfid:%d onuid:%d", msg.IntfId, msg.OnuId)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +090095 }
96 case <-ctx.Done():
97 return
98 }
99 }
100 }()
101}
102
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900103func respondMessage(msgtype string, client clientInstance, recvmsg *byteMsg, msgInCh chan *byteMsg) clientState {
104 curstate := client.getState()
105 nextstate, sendbytes, err := client.transitState(curstate, recvmsg.Byte)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900106
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900107 if err != nil {
108 msg := fmt.Sprintf("Failed to transitState in %s: %s", msgtype, err)
109 logger.Error(msg, err)
110 }
111
112 if sendbytes != nil {
113 key := client.getKey()
114 if err := sendBytes(key, sendbytes, msgInCh); err != nil {
115 msg := fmt.Sprintf("Failed to sendBytes in %s: %s", msgtype, err)
116 logger.Error(msg)
117 }
118 } else {
119 logger.Debug("sendbytes is nil")
120 }
121 return nextstate
122}
123
124func startEAPClient(intfid uint32, onuid uint32) error {
125 client := eapClientInstance{key: clientKey{intfid: intfid, onuid: onuid},
126 srcaddr: &net.HardwareAddr{0x2e, 0x60, 0x70, 0x13, 0x07, byte(onuid)},
127 version: 1,
128 curId: 0,
129 curState: EAP_START}
130
131 eap := client.createEAPStart()
132 bytes := client.createEAPOL(eap)
133 resp := getEAPResponder()
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900134 eapolIn := resp.eapolIn
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900135 if err := sendBytes(clientKey{intfid, onuid}, bytes, eapolIn); err != nil {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900136 return errors.New("Failed to send EAPStart")
137 }
138 logger.Debug("Sending EAPStart")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900139 //clients[key{intfid: intfid, onuid: onuid}] = &client
140 resp.clients[clientKey{intfid: intfid, onuid: onuid}] = &client
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900141 return nil
142}
143
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900144func (c eapClientInstance) transitState(cur clientState, recvbytes []byte) (next clientState, respbytes []byte, err error) {
145 recvpkt := gopacket.NewPacket(recvbytes, layers.LayerTypeEthernet, gopacket.Default)
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900146 eap, err := extractEAP(recvpkt)
147 if err != nil {
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900148 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900149 }
150 if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeIdentity {
151 logger.Debug("Received EAP-Request/Identity")
152 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900153 c.curId = eap.Id
154 if cur == EAP_START {
155 reseap := c.createEAPResID()
156 pkt := c.createEAPOL(reseap)
157 return EAP_RESPID, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900158 }
159 } else if eap.Code == layers.EAPCodeRequest && eap.Type == layers.EAPTypeOTP {
160 logger.Debug("Received EAP-Request/Challenge")
161 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900162 if cur == EAP_RESPID {
163 c.curId = eap.Id
164 senddata := getMD5Data(c.curId, eap)
165 senddata = append([]byte{0x10}, senddata...)
166 sendeap := c.createEAPResCha(senddata)
167 pkt := c.createEAPOL(sendeap)
168 return EAP_RESPCHA, pkt, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900169 }
170 } else if eap.Code == layers.EAPCodeSuccess && eap.Type == layers.EAPTypeNone {
171 logger.Debug("Received EAP-Success")
172 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900173 if cur == EAP_RESPCHA {
174 return EAP_SUCCESS, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900175 }
176 } else {
177 logger.Debug("Received unsupported EAP")
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900178 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900179 }
180 logger.Debug("State transition does not support..current state:%d", cur)
181 logger.Debug(recvpkt.Dump())
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900182 return cur, nil, nil
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900183}
184
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900185func (c eapClientInstance) getState() clientState {
186 return c.curState
187}
188
189func (c *eapClientInstance) updateState(state clientState) {
190 msg := fmt.Sprintf("EAP update state intfid:%d onuid:%d state:%d", c.key.intfid, c.key.onuid, state)
191 logger.Debug(msg)
192 c.curState = state
193}
194
195func (c eapClientInstance) getKey() clientKey {
196 return c.key
197}
198
199func sendBytes(key clientKey, pkt []byte, chIn chan *byteMsg) error {
200 // Send our packet
201 msg := byteMsg{IntfId: key.intfid,
202 OnuId: key.onuid,
203 Byte: pkt}
204 chIn <- &msg
205 logger.Debug("sendBytes intfid:%d onuid:%d", key.intfid, key.onuid)
206 logger.Debug(hex.Dump(msg.Byte))
207 return nil
208}
209
210func (c *eapClientInstance) createEAPOL(eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900211 buffer := gopacket.NewSerializeBuffer()
212 options := gopacket.SerializeOptions{}
213
214 ethernetLayer := &layers.Ethernet{
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900215 SrcMAC: *c.srcaddr,
216 DstMAC: net.HardwareAddr{0x01, 0x80, 0xC2, 0x00, 0x00, 0x03},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900217 EthernetType: layers.EthernetTypeEAPOL,
218 }
219
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900220 if eap == nil { // EAP Start
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900221 gopacket.SerializeLayers(buffer, options,
222 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900223 &layers.EAPOL{Version: c.version, Type: 1, Length: 0},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900224 )
225 } else {
226 gopacket.SerializeLayers(buffer, options,
227 ethernetLayer,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900228 &layers.EAPOL{Version: c.version, Type: 0, Length: eap.Length},
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900229 eap,
230 )
231 }
232 bytes := buffer.Bytes()
233 return bytes
234}
235
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900236func (c *eapClientInstance) createEAPStart() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900237 return nil
238}
239
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900240func (c *eapClientInstance) createEAPResID() *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900241 eap := layers.EAP{Code: layers.EAPCodeResponse,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900242 Id: c.curId,
243 Length: 9,
244 Type: layers.EAPTypeIdentity,
245 TypeData: []byte{0x75, 0x73, 0x65, 0x72}}
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900246 return &eap
247}
248
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900249func (c *eapClientInstance) createEAPResCha(payload []byte) *layers.EAP {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900250 eap := layers.EAP{Code: layers.EAPCodeResponse,
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900251 Id: c.curId, Length: 22,
252 Type: layers.EAPTypeOTP,
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900253 TypeData: payload}
254 return &eap
255}
256
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900257func getMD5Data (id uint8, eap *layers.EAP) []byte {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900258 i := byte(id)
259 C := []byte(eap.BaseLayer.Contents)[6:]
260 P := []byte{i, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64} //"password"
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900261 data := md5.Sum(append(P, C...))
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900262 ret := make([]byte, 16)
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900263 for j := 0; j < 16; j++ {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900264 ret[j] = data[j]
265 }
266 return ret
267}
268
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900269func extractEAPOL(pkt gopacket.Packet) (*layers.EAPOL, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900270 layerEAPOL := pkt.Layer(layers.LayerTypeEAPOL)
271 eapol, _ := layerEAPOL.(*layers.EAPOL)
272 if eapol == nil {
273 return nil, errors.New("Cannot extract EAPOL")
274 }
275 return eapol, nil
276}
277
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900278func extractEAP(pkt gopacket.Packet) (*layers.EAP, error) {
Keita NISHIMOTO621a43d2019-01-30 20:53:03 +0900279 layerEAP := pkt.Layer(layers.LayerTypeEAP)
280 eap, _ := layerEAP.(*layers.EAP)
281 if eap == nil {
282 return nil, errors.New("Cannot extract EAP")
283 }
284 return eap, nil
Keita NISHIMOTOdad44cb2019-02-08 09:45:40 +0900285}