blob: 479ec7ed664db53b21a423489d6269e51023e042 [file] [log] [blame]
Ari Saha89831742015-06-26 10:31:48 -07001/*
2 * Copyright 2015 AT&T Foundry
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 */
16package org.onosproject.aaa;
17
Ray Milkeyf61a24e2015-09-24 16:34:02 -070018import java.net.InetAddress;
Ray Milkeyf61a24e2015-09-24 16:34:02 -070019import java.nio.ByteBuffer;
Ray Milkeyf61a24e2015-09-24 16:34:02 -070020import java.util.Optional;
21import java.util.Set;
22
Ari Saha89831742015-06-26 10:31:48 -070023import org.apache.felix.scr.annotations.Activate;
24import org.apache.felix.scr.annotations.Component;
25import org.apache.felix.scr.annotations.Deactivate;
Ari Saha89831742015-06-26 10:31:48 -070026import org.apache.felix.scr.annotations.Reference;
27import org.apache.felix.scr.annotations.ReferenceCardinality;
Jonathan Harta46dddf2015-06-30 15:31:20 -070028import org.onlab.packet.DeserializationException;
29import org.onlab.packet.EAP;
30import org.onlab.packet.EAPOL;
31import org.onlab.packet.EthType;
Ari Saha89831742015-06-26 10:31:48 -070032import org.onlab.packet.Ethernet;
33import org.onlab.packet.IPv4;
34import org.onlab.packet.Ip4Address;
35import org.onlab.packet.IpAddress;
36import org.onlab.packet.MacAddress;
Jonathan Harta46dddf2015-06-30 15:31:20 -070037import org.onlab.packet.RADIUS;
38import org.onlab.packet.RADIUSAttribute;
Hyunsun Moona0d63712015-08-22 21:04:23 -070039import org.onlab.packet.TpPort;
Ari Saha89831742015-06-26 10:31:48 -070040import org.onlab.packet.UDP;
41import org.onlab.packet.VlanId;
Ari Saha89831742015-06-26 10:31:48 -070042import org.onosproject.core.ApplicationId;
43import org.onosproject.core.CoreService;
44import org.onosproject.net.ConnectPoint;
45import org.onosproject.net.DeviceId;
46import org.onosproject.net.Host;
47import org.onosproject.net.PortNumber;
Ray Milkeyfcb623d2015-10-01 16:48:18 -070048import org.onosproject.net.config.ConfigFactory;
49import org.onosproject.net.config.NetworkConfigEvent;
50import org.onosproject.net.config.NetworkConfigListener;
51import org.onosproject.net.config.NetworkConfigRegistry;
Ari Saha89831742015-06-26 10:31:48 -070052import org.onosproject.net.flow.DefaultTrafficSelector;
53import org.onosproject.net.flow.DefaultTrafficTreatment;
Ari Saha89831742015-06-26 10:31:48 -070054import org.onosproject.net.flow.TrafficSelector;
55import org.onosproject.net.flow.TrafficTreatment;
56import org.onosproject.net.host.HostService;
Ari Saha89831742015-06-26 10:31:48 -070057import org.onosproject.net.packet.DefaultOutboundPacket;
58import org.onosproject.net.packet.InboundPacket;
59import org.onosproject.net.packet.OutboundPacket;
60import org.onosproject.net.packet.PacketContext;
Ari Saha89831742015-06-26 10:31:48 -070061import org.onosproject.net.packet.PacketProcessor;
62import org.onosproject.net.packet.PacketService;
Ari Saha89831742015-06-26 10:31:48 -070063import org.onosproject.xosintegration.VoltTenantService;
Ari Saha89831742015-06-26 10:31:48 -070064import org.slf4j.Logger;
65
Ray Milkeyfcb623d2015-10-01 16:48:18 -070066import static org.onosproject.net.config.basics.SubjectFactories.APP_SUBJECT_FACTORY;
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -070067import static org.onosproject.net.packet.PacketPriority.CONTROL;
Ari Saha89831742015-06-26 10:31:48 -070068import static org.slf4j.LoggerFactory.getLogger;
69
Ari Saha89831742015-06-26 10:31:48 -070070/**
Jonathan Harta46dddf2015-06-30 15:31:20 -070071 * AAA application for ONOS.
Ari Saha89831742015-06-26 10:31:48 -070072 */
73@Component(immediate = true)
74public class AAA {
Ray Milkeyf51eba22015-09-25 10:24:23 -070075
Ray Milkeyf61a24e2015-09-24 16:34:02 -070076 // for verbose output
77 private final Logger log = getLogger(getClass());
Ray Milkeyf51eba22015-09-25 10:24:23 -070078
Ray Milkeyf61a24e2015-09-24 16:34:02 -070079 // a list of our dependencies :
80 // to register with ONOS as an application - described next
81 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
82 protected CoreService coreService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070083
Ray Milkeyf61a24e2015-09-24 16:34:02 -070084 // to receive Packet-in events that we'll respond to
85 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
86 protected PacketService packetService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070087
Ray Milkeyf61a24e2015-09-24 16:34:02 -070088 // end host information
89 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
90 protected HostService hostService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070091
Ray Milkeyf61a24e2015-09-24 16:34:02 -070092 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
93 protected VoltTenantService voltTenantService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070094
95 @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
Ray Milkeyfcb623d2015-10-01 16:48:18 -070096 protected NetworkConfigRegistry netCfgService;
Ray Milkeyf51eba22015-09-25 10:24:23 -070097
Ray Milkeyfcb623d2015-10-01 16:48:18 -070098 // Parsed RADIUS server addresses
99 protected InetAddress radiusIpAddress;
100 protected String radiusMacAddress;
101
102 // NAS IP address
103 protected InetAddress nasIpAddress;
104 protected String nasMacAddress;
105
106 // RADIUS server secret
107 protected String radiusSecret;
108
109 // ID of RADIUS switch
110 protected String radiusSwitch;
111
112 // RADIUS port number
113 protected long radiusPort;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700114
Ray Milkey5d99bd12015-10-06 15:41:30 -0700115 // RADIUS server TCP port number
116 protected short radiusServerPort;
117
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700118 // our application-specific event handler
119 private ReactivePacketProcessor processor = new ReactivePacketProcessor();
Ray Milkeyf51eba22015-09-25 10:24:23 -0700120
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700121 // our unique identifier
122 private ApplicationId appId;
Ray Milkeyf51eba22015-09-25 10:24:23 -0700123
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700124 // Configuration properties factory
125 private final ConfigFactory factory =
126 new ConfigFactory<ApplicationId, AAAConfig>(APP_SUBJECT_FACTORY,
127 AAAConfig.class,
128 "AAA") {
129 @Override
130 public AAAConfig createConfig() {
131 return new AAAConfig();
132 }
133 };
Ray Milkeyf51eba22015-09-25 10:24:23 -0700134
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700135 // Listener for config changes
136 private final InternalConfigListener cfgListener = new InternalConfigListener();
Ari Saha89831742015-06-26 10:31:48 -0700137
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700138 /**
139 * Builds an EAPOL packet based on the given parameters.
140 *
141 * @param dstMac destination MAC address
142 * @param srcMac source MAC address
143 * @param vlan vlan identifier
144 * @param eapolType EAPOL type
145 * @param eap EAP payload
146 * @return Ethernet frame
147 */
148 private static Ethernet buildEapolResponse(MacAddress dstMac, MacAddress srcMac,
149 short vlan, byte eapolType, EAP eap) {
Ari Saha89831742015-06-26 10:31:48 -0700150
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700151 Ethernet eth = new Ethernet();
152 eth.setDestinationMACAddress(dstMac.toBytes());
153 eth.setSourceMACAddress(srcMac.toBytes());
154 eth.setEtherType(EthType.EtherType.EAPOL.ethType().toShort());
155 if (vlan != Ethernet.VLAN_UNTAGGED) {
156 eth.setVlanID(vlan);
157 }
158 //eapol header
159 EAPOL eapol = new EAPOL();
160 eapol.setEapolType(eapolType);
161 eapol.setPacketLength(eap.getLength());
Ari Saha89831742015-06-26 10:31:48 -0700162
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700163 //eap part
164 eapol.setPayload(eap);
165
166 eth.setPayload(eapol);
167 eth.setPad(true);
168 return eth;
169 }
Ari Saha89831742015-06-26 10:31:48 -0700170
Ari Saha89831742015-06-26 10:31:48 -0700171 @Activate
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700172 public void activate() {
173 netCfgService.addListener(cfgListener);
174 netCfgService.registerConfigFactory(factory);
175
Ari Saha89831742015-06-26 10:31:48 -0700176 // "org.onosproject.aaa" is the FQDN of our app
177 appId = coreService.registerApplication("org.onosproject.aaa");
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700178
179 cfgListener.reconfigureNetwork(netCfgService.getConfig(appId, AAAConfig.class));
180
Ari Saha89831742015-06-26 10:31:48 -0700181 // register our event handler
Brian O'Connord9c7da02015-07-29 17:49:24 -0700182 packetService.addProcessor(processor, PacketProcessor.director(2));
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700183 requestIntercepts();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700184
185 StateMachine.initializeMaps();
Ari Saha89831742015-06-26 10:31:48 -0700186
187 hostService.startMonitoringIp(IpAddress.valueOf(radiusIpAddress));
Ari Saha89831742015-06-26 10:31:48 -0700188 }
189
190 @Deactivate
191 public void deactivate() {
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700192 appId = coreService.registerApplication("org.onosproject.aaa");
193 withdrawIntercepts();
Ari Saha89831742015-06-26 10:31:48 -0700194 // de-register and null our handler
195 packetService.removeProcessor(processor);
196 processor = null;
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700197 StateMachine.destroyMaps();
Ari Saha89831742015-06-26 10:31:48 -0700198 }
199
Jonathan Harta46dddf2015-06-30 15:31:20 -0700200 /**
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700201 * Request packet in via PacketService.
202 */
203 private void requestIntercepts() {
204 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
205 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
206 packetService.requestPackets(selector.build(),
207 CONTROL, appId);
Jonathan Hartfeb41762015-07-15 15:10:28 -0700208
209 TrafficSelector radSelector = DefaultTrafficSelector.builder()
210 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
211 .matchIPProtocol(IPv4.PROTOCOL_UDP)
Ray Milkey5d99bd12015-10-06 15:41:30 -0700212 .matchUdpDst(TpPort.tpPort(radiusServerPort))
213 .matchUdpSrc(TpPort.tpPort(radiusServerPort))
Jonathan Hartfeb41762015-07-15 15:10:28 -0700214 .build();
215 packetService.requestPackets(radSelector, CONTROL, appId);
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700216 }
217
218 /**
219 * Cancel request for packet in via PacketService.
220 */
221 private void withdrawIntercepts() {
222 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
223 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
224 packetService.cancelPackets(selector.build(), CONTROL, appId);
Jonathan Hartfeb41762015-07-15 15:10:28 -0700225
226 TrafficSelector radSelector = DefaultTrafficSelector.builder()
227 .matchEthType(EthType.EtherType.IPV4.ethType().toShort())
228 .matchIPProtocol(IPv4.PROTOCOL_UDP)
Ray Milkey5d99bd12015-10-06 15:41:30 -0700229 .matchUdpDst(TpPort.tpPort(radiusServerPort))
230 .matchUdpSrc(TpPort.tpPort(radiusServerPort))
Jonathan Hartfeb41762015-07-15 15:10:28 -0700231 .build();
232 packetService.cancelPackets(radSelector, CONTROL, appId);
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700233 }
234
Ari Saha89831742015-06-26 10:31:48 -0700235 // our handler defined as a private inner class
236
237 /**
238 * Packet processor responsible for forwarding packets along their paths.
239 */
240 private class ReactivePacketProcessor implements PacketProcessor {
241 @Override
242 public void process(PacketContext context) {
243
244 // Extract the original Ethernet frame from the packet information
245 InboundPacket pkt = context.inPacket();
246 Ethernet ethPkt = pkt.parsed();
247 if (ethPkt == null) {
248 return;
249 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700250 try {
251 // identify if incoming packet comes from supplicant (EAP) or RADIUS
252 switch (EthType.EtherType.lookup(ethPkt.getEtherType())) {
253 case EAPOL:
254 handleSupplicantPacket(context.inPacket());
255 break;
256 case IPV4:
257 IPv4 ipv4Packet = (IPv4) ethPkt.getPayload();
258 Ip4Address srcIp = Ip4Address.valueOf(ipv4Packet.getSourceAddress());
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700259 Ip4Address radiusIp4Address = Ip4Address.valueOf(radiusIpAddress);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700260 if (srcIp.equals(radiusIp4Address) && ipv4Packet.getProtocol() == IPv4.PROTOCOL_UDP) {
261 // TODO: check for port as well when it's configurable
262 UDP udpPacket = (UDP) ipv4Packet.getPayload();
Jonathan Harta46dddf2015-06-30 15:31:20 -0700263
Ray Milkeyf51eba22015-09-25 10:24:23 -0700264 byte[] datagram = udpPacket.getPayload().serialize();
265 RADIUS radiusPacket;
Jonathan Harta46dddf2015-06-30 15:31:20 -0700266 radiusPacket = RADIUS.deserializer().deserialize(datagram, 0, datagram.length);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700267 handleRadiusPacket(radiusPacket);
Jonathan Harta46dddf2015-06-30 15:31:20 -0700268 }
Ray Milkeyf51eba22015-09-25 10:24:23 -0700269
270 break;
271 default:
272 log.trace("Skipping Ethernet packet type {}",
273 EthType.EtherType.lookup(ethPkt.getEtherType()));
274 }
275 } catch (DeserializationException | StateMachineException e) {
276 log.warn("Unable to process RADIUS packet:", e);
Ari Saha89831742015-06-26 10:31:48 -0700277 }
278 }
279
Ray Milkey9eb293f2015-09-30 15:09:17 -0700280 /**
281 * Creates and initializes common fields of a RADIUS packet.
282 *
283 * @param identifier RADIUS identifier
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700284 * @param eapPacket EAP packet
Ray Milkey9eb293f2015-09-30 15:09:17 -0700285 * @return RADIUS packet
286 */
287 private RADIUS getRadiusPayload(byte identifier, EAP eapPacket) {
288 RADIUS radiusPayload =
289 new RADIUS(RADIUS.RADIUS_CODE_ACCESS_REQUEST,
290 eapPacket.getIdentifier());
291 radiusPayload.setIdentifier(identifier);
292 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_USERNAME,
293 eapPacket.getData());
294
295 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_NAS_IP,
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700296 AAA.this.nasIpAddress.getAddress());
Ray Milkey9eb293f2015-09-30 15:09:17 -0700297
298 radiusPayload.encapsulateMessage(eapPacket);
299 radiusPayload.addMessageAuthenticator(AAA.this.radiusSecret);
300
301 return radiusPayload;
302 }
Ari Saha89831742015-06-26 10:31:48 -0700303
304 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700305 * Handles PAE packets (supplicant).
306 *
307 * @param inPacket Ethernet packet coming from the supplicant
Ari Saha89831742015-06-26 10:31:48 -0700308 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700309 private void handleSupplicantPacket(InboundPacket inPacket) throws StateMachineException {
Jonathan Harta46dddf2015-06-30 15:31:20 -0700310 Ethernet ethPkt = inPacket.parsed();
Ari Saha89831742015-06-26 10:31:48 -0700311 // Where does it come from?
312 MacAddress srcMAC = ethPkt.getSourceMAC();
313
Jonathan Harta46dddf2015-06-30 15:31:20 -0700314 DeviceId deviceId = inPacket.receivedFrom().deviceId();
315 PortNumber portNumber = inPacket.receivedFrom().port();
Ari Saha89831742015-06-26 10:31:48 -0700316 String sessionId = deviceId.toString() + portNumber.toString();
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700317 StateMachine stateMachine = StateMachine.lookupStateMachineBySessionId(sessionId);
318 if (stateMachine == null) {
319 stateMachine = new StateMachine(sessionId, voltTenantService);
320 }
321
Jonathan Harta46dddf2015-06-30 15:31:20 -0700322
323 EAPOL eapol = (EAPOL) ethPkt.getPayload();
Ari Saha89831742015-06-26 10:31:48 -0700324
325 switch (eapol.getEapolType()) {
326 case EAPOL.EAPOL_START:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700327 stateMachine.start();
328 stateMachine.setSupplicantConnectpoint(inPacket.receivedFrom());
Ari Saha89831742015-06-26 10:31:48 -0700329
Ray Milkeyf51eba22015-09-25 10:24:23 -0700330 //send an EAP Request/Identify to the supplicant
331 EAP eapPayload = new EAP(EAP.REQUEST, stateMachine.identifier(), EAP.ATTR_IDENTITY, null);
332 Ethernet eth = buildEapolResponse(srcMAC, MacAddress.valueOf(1L),
333 ethPkt.getVlanID(), EAPOL.EAPOL_PACKET,
334 eapPayload);
335 stateMachine.setSupplicantAddress(srcMAC);
336 stateMachine.setVlanId(ethPkt.getVlanID());
Ari Saha89831742015-06-26 10:31:48 -0700337
Ray Milkeyf51eba22015-09-25 10:24:23 -0700338 this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700339
340 break;
341 case EAPOL.EAPOL_PACKET:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700342 RADIUS radiusPayload;
Ray Milkey9eb293f2015-09-30 15:09:17 -0700343 // check if this is a Response/Identify or a Response/TLS
Ari Saha89831742015-06-26 10:31:48 -0700344 EAP eapPacket = (EAP) eapol.getPayload();
345
346 byte dataType = eapPacket.getDataType();
347 switch (dataType) {
Ari Saha89831742015-06-26 10:31:48 -0700348
Ray Milkey9eb293f2015-09-30 15:09:17 -0700349 case EAP.ATTR_IDENTITY:
350 // request id access to RADIUS
351 stateMachine.setUsername(eapPacket.getData());
Ari Saha89831742015-06-26 10:31:48 -0700352
Ray Milkey9eb293f2015-09-30 15:09:17 -0700353 radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700354
Ray Milkey9eb293f2015-09-30 15:09:17 -0700355 // set Request Authenticator in StateMachine
356 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
357 sendRadiusMessage(radiusPayload);
Ray Milkeyf51eba22015-09-25 10:24:23 -0700358
Ray Milkey9eb293f2015-09-30 15:09:17 -0700359 // change the state to "PENDING"
360 stateMachine.requestAccess();
361 break;
Ari Saha89831742015-06-26 10:31:48 -0700362 case EAP.ATTR_MD5:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700363 // verify if the EAP identifier corresponds to the
364 // challenge identifier from the client state
365 // machine.
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700366 if (eapPacket.getIdentifier() == stateMachine.challengeIdentifier()) {
Ari Saha89831742015-06-26 10:31:48 -0700367 //send the RADIUS challenge response
Ray Milkey9eb293f2015-09-30 15:09:17 -0700368 radiusPayload = getRadiusPayload(stateMachine.challengeIdentifier(), eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700369
370 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700371 stateMachine.challengeState());
Ari Saha89831742015-06-26 10:31:48 -0700372 sendRadiusMessage(radiusPayload);
373 }
374 break;
375 case EAP.ATTR_TLS:
Ray Milkey9eb293f2015-09-30 15:09:17 -0700376 // request id access to RADIUS
377 radiusPayload = getRadiusPayload(stateMachine.identifier(), eapPacket);
Ari Saha89831742015-06-26 10:31:48 -0700378
Ray Milkeyf51eba22015-09-25 10:24:23 -0700379 radiusPayload.setAttribute(RADIUSAttribute.RADIUS_ATTR_STATE,
380 stateMachine.challengeState());
381 stateMachine.setRequestAuthenticator(radiusPayload.generateAuthCode());
Ari Saha89831742015-06-26 10:31:48 -0700382
Ray Milkeyf51eba22015-09-25 10:24:23 -0700383 sendRadiusMessage(radiusPayload);
384 // TODO: this gets called on every fragment, should only be called at TLS-Start
385 stateMachine.requestAccess();
386
Ari Saha89831742015-06-26 10:31:48 -0700387 break;
388 default:
389 return;
390 }
391 break;
392 default:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700393 log.trace("Skipping EAPOL message {}", eapol.getEapolType());
Ari Saha89831742015-06-26 10:31:48 -0700394 }
395 }
396
397 /**
Jonathan Harta46dddf2015-06-30 15:31:20 -0700398 * Handles RADIUS packets.
399 *
Ari Saha89831742015-06-26 10:31:48 -0700400 * @param radiusPacket RADIUS packet coming from the RADIUS server.
401 */
Ray Milkeyf51eba22015-09-25 10:24:23 -0700402 private void handleRadiusPacket(RADIUS radiusPacket) throws StateMachineException {
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700403 StateMachine stateMachine = StateMachine.lookupStateMachineById(radiusPacket.getIdentifier());
Ari Saha89831742015-06-26 10:31:48 -0700404 if (stateMachine == null) {
405 log.error("Invalid session identifier, exiting...");
406 return;
407 }
408
Ray Milkeyf51eba22015-09-25 10:24:23 -0700409 EAP eapPayload;
410 Ethernet eth;
Ari Saha89831742015-06-26 10:31:48 -0700411 switch (radiusPacket.getCode()) {
412 case RADIUS.RADIUS_CODE_ACCESS_CHALLENGE:
413 byte[] challengeState = radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_STATE).getValue();
414 eapPayload = radiusPacket.decapsulateMessage();
415 stateMachine.setChallengeInfo(eapPayload.getIdentifier(), challengeState);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700416 eth = buildEapolResponse(stateMachine.supplicantAddress(),
417 MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET,
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700418 eapPayload);
Ray Milkeyf61a24e2015-09-24 16:34:02 -0700419 this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700420 break;
421 case RADIUS.RADIUS_CODE_ACCESS_ACCEPT:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700422 //send an EAPOL - Success to the supplicant.
423 byte[] eapMessage =
424 radiusPacket.getAttribute(RADIUSAttribute.RADIUS_ATTR_EAP_MESSAGE).getValue();
425 eapPayload = new EAP();
426 eapPayload = (EAP) eapPayload.deserialize(eapMessage, 0, eapMessage.length);
427 eth = buildEapolResponse(stateMachine.supplicantAddress(),
428 MacAddress.valueOf(1L), stateMachine.vlanId(), EAPOL.EAPOL_PACKET,
429 eapPayload);
430 this.sendPacketToSupplicant(eth, stateMachine.supplicantConnectpoint());
Ari Saha89831742015-06-26 10:31:48 -0700431
Ray Milkeyf51eba22015-09-25 10:24:23 -0700432 stateMachine.authorizeAccess();
Ari Saha89831742015-06-26 10:31:48 -0700433 break;
434 case RADIUS.RADIUS_CODE_ACCESS_REJECT:
Ray Milkeyf51eba22015-09-25 10:24:23 -0700435 stateMachine.denyAccess();
Ari Saha89831742015-06-26 10:31:48 -0700436 break;
437 default:
438 log.warn("Unknown RADIUS message received with code: {}", radiusPacket.getCode());
439 }
440 }
441
Ari Saha89831742015-06-26 10:31:48 -0700442 private void sendRadiusMessage(RADIUS radiusMessage) {
443 Set<Host> hosts = hostService.getHostsByIp(IpAddress.valueOf(radiusIpAddress));
444 Optional<Host> odst = hosts.stream().filter(h -> h.vlan().toShort() == VlanId.UNTAGGED).findFirst();
445
446 Host dst;
447 if (!odst.isPresent()) {
448 log.info("Radius server {} is not present", radiusIpAddress);
449 return;
450 } else {
451 dst = odst.get();
452 }
453
454 UDP udp = new UDP();
455 IPv4 ip4Packet = new IPv4();
456 Ethernet ethPkt = new Ethernet();
457 radiusMessage.setParent(udp);
Ray Milkey5d99bd12015-10-06 15:41:30 -0700458 udp.setDestinationPort(radiusServerPort);
459 udp.setSourcePort(radiusServerPort);
Ari Saha89831742015-06-26 10:31:48 -0700460 udp.setPayload(radiusMessage);
461 udp.setParent(ip4Packet);
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700462 ip4Packet.setSourceAddress(AAA.this.nasIpAddress.getHostAddress());
463 ip4Packet.setDestinationAddress(AAA.this.radiusIpAddress.getHostAddress());
Ari Saha89831742015-06-26 10:31:48 -0700464 ip4Packet.setProtocol(IPv4.PROTOCOL_UDP);
465 ip4Packet.setPayload(udp);
466 ip4Packet.setParent(ethPkt);
467 ethPkt.setDestinationMACAddress(radiusMacAddress);
468 ethPkt.setSourceMACAddress(nasMacAddress);
469 ethPkt.setEtherType(Ethernet.TYPE_IPV4);
470 ethPkt.setPayload(ip4Packet);
471
472 TrafficTreatment treatment = DefaultTrafficTreatment.builder()
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700473 .setOutput(PortNumber.portNumber(radiusPort)).build();
Ari Saha89831742015-06-26 10:31:48 -0700474 OutboundPacket packet = new DefaultOutboundPacket(DeviceId.deviceId(radiusSwitch),
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700475 treatment, ByteBuffer.wrap(ethPkt.serialize()));
Ari Saha89831742015-06-26 10:31:48 -0700476 packetService.emit(packet);
477
478 }
479
Ari Saha89831742015-06-26 10:31:48 -0700480 /**
481 * Send the ethernet packet to the supplicant.
Jonathan Harta46dddf2015-06-30 15:31:20 -0700482 *
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700483 * @param ethernetPkt the ethernet packet
Jonathan Harta46dddf2015-06-30 15:31:20 -0700484 * @param connectPoint the connect point to send out
Ari Saha89831742015-06-26 10:31:48 -0700485 */
486 private void sendPacketToSupplicant(Ethernet ethernetPkt, ConnectPoint connectPoint) {
487 TrafficTreatment treatment = DefaultTrafficTreatment.builder().setOutput(connectPoint.port()).build();
488 OutboundPacket packet = new DefaultOutboundPacket(connectPoint.deviceId(),
Aaron Kruglikovd39d99e2015-07-03 13:30:57 -0700489 treatment, ByteBuffer.wrap(ethernetPkt.serialize()));
Ari Saha89831742015-06-26 10:31:48 -0700490 packetService.emit(packet);
491 }
492
493 }
494
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700495 private class InternalConfigListener implements NetworkConfigListener {
496
497 /**
498 * Reconfigures the DHCP Server according to the configuration parameters passed.
499 *
500 * @param cfg configuration object
501 */
502 private void reconfigureNetwork(AAAConfig cfg) {
503 AAAConfig newCfg;
504 if (cfg == null) {
505 newCfg = new AAAConfig();
506 } else {
507 newCfg = cfg;
508 }
509 if (newCfg.nasIp() != null) {
510 nasIpAddress = newCfg.nasIp();
511 }
512 if (newCfg.radiusIp() != null) {
513 radiusIpAddress = newCfg.radiusIp();
514 }
515 if (newCfg.radiusMac() != null) {
516 radiusMacAddress = newCfg.radiusMac();
517 }
518 if (newCfg.nasMac() != null) {
519 nasMacAddress = newCfg.nasMac();
520 }
521 if (newCfg.radiusSecret() != null) {
522 radiusSecret = newCfg.radiusSecret();
523 }
524 if (newCfg.radiusSwitch() != null) {
525 radiusSwitch = newCfg.radiusSwitch();
526 }
527 if (newCfg.radiusPort() != -1) {
528 radiusPort = newCfg.radiusPort();
529 }
Ray Milkey5d99bd12015-10-06 15:41:30 -0700530 if (newCfg.radiusServerUDPPort() != -1) {
531 radiusServerPort = newCfg.radiusServerUDPPort();
532 }
Ray Milkeyfcb623d2015-10-01 16:48:18 -0700533 }
534
535 @Override
536 public void event(NetworkConfigEvent event) {
537
538 if ((event.type() == NetworkConfigEvent.Type.CONFIG_ADDED ||
539 event.type() == NetworkConfigEvent.Type.CONFIG_UPDATED) &&
540 event.configClass().equals(AAAConfig.class)) {
541
542 AAAConfig cfg = netCfgService.getConfig(appId, AAAConfig.class);
543 reconfigureNetwork(cfg);
544 log.info("Reconfigured");
545 }
546 }
547 }
548
549
Ari Saha89831742015-06-26 10:31:48 -0700550}