blob: 6b64a187f629b624eb54cb7cbad83f55d6e9d7c0 [file] [log] [blame]
Amit Ghoshc9ac1e52017-07-28 12:31:18 +01001/*
2 * Copyright 2017-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 */
16package org.opencord.aaa;
17
18import org.onlab.packet.DeserializationException;
19import org.onlab.packet.EthType;
20import org.onlab.packet.Ethernet;
21import org.onlab.packet.RADIUS;
22
23import org.onosproject.core.ApplicationId;
24import org.onosproject.net.flow.DefaultTrafficSelector;
25import org.onosproject.net.flow.TrafficSelector;
26import org.onosproject.net.packet.InboundPacket;
27import org.onosproject.net.packet.PacketContext;
28import org.onosproject.net.packet.PacketService;
29
30import org.slf4j.Logger;
31
32import com.google.common.util.concurrent.ThreadFactoryBuilder;
33
34import static org.onosproject.net.packet.PacketPriority.CONTROL;
35import static org.slf4j.LoggerFactory.getLogger;
36
37import java.io.IOException;
38import java.net.DatagramPacket;
39import java.net.DatagramSocket;
40import java.net.InetAddress;
41import java.net.InetSocketAddress;
42import java.util.concurrent.ExecutorService;
43import java.util.concurrent.Executors;
44
45/**
46 * Handles Socket based communication with the RADIUS server.
47 */
48public class SocketBasedRadiusCommunicator implements RadiusCommunicator {
49
50 // for verbose output
51 private final Logger log = getLogger(getClass());
52
53 // our unique identifier
54 private ApplicationId appId;
55
56 // to receive Packet-in events that we'll respond to
57 PacketService packetService;
58
59 // Socket used for UDP communications with RADIUS server
60 private DatagramSocket radiusSocket;
61
62 // Parsed RADIUS server addresses
63 protected InetAddress radiusIpAddress;
64
65 // RADIUS server TCP port number
66 protected short radiusServerPort;
67
68 // Executor for RADIUS communication thread
69 private ExecutorService executor;
70
71 AaaManager aaaManager;
72
73 SocketBasedRadiusCommunicator(ApplicationId appId, PacketService pktService,
74 AaaManager aaaManager) {
75 this.appId = appId;
76 this.packetService = pktService;
77 this.aaaManager = aaaManager;
78 }
79
80 @Override
81 public void initializeLocalState(AaaConfig newCfg) {
82 if (newCfg.radiusIp() != null) {
83 radiusIpAddress = newCfg.radiusIp();
84 }
85 radiusServerPort = newCfg.radiusServerUdpPort();
86
87 try {
88 radiusSocket = new DatagramSocket(null);
89 radiusSocket.setReuseAddress(true);
90 radiusSocket.bind(new InetSocketAddress(radiusServerPort));
91 } catch (Exception ex) {
92 log.error("Can't open RADIUS socket", ex);
93 }
94
Matt Jeanneret2ff1a782018-06-13 15:24:25 -040095 log.info("Remote RADIUS Server: {}:{}", radiusIpAddress, radiusServerPort);
96
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010097 executor = Executors.newSingleThreadExecutor(
98 new ThreadFactoryBuilder()
99 .setNameFormat("AAA-radius-%d").build());
100 executor.execute(radiusListener);
101 }
102
103 @Override
104 public void clearLocalState() {
105 radiusSocket.close();
106 executor.shutdownNow();
107 }
108
109 @Override
Deepa Vaddireddyd87f2872017-10-24 07:58:11 +0000110 public void deactivate() {
111 clearLocalState();
112 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100113
114 @Override
115 public void requestIntercepts() {
116 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
117 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
118 packetService.requestPackets(selector.build(), CONTROL, appId);
119 }
120
121 @Override
122 public void withdrawIntercepts() {
123 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
124 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
125 packetService.cancelPackets(selector.build(), CONTROL, appId);
126 }
127
128 @Override
129 public void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
130 try {
131 final byte[] data = radiusPacket.serialize();
132 final DatagramSocket socket = radiusSocket;
133
134 DatagramPacket packet =
135 new DatagramPacket(data, data.length,
136 radiusIpAddress, radiusServerPort);
137
138 socket.send(packet);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400139 log.debug("Packet sent to Radius Server {}:{} using socket",
140 radiusIpAddress, radiusServerPort);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100141 } catch (IOException e) {
142 log.info("Cannot send packet to RADIUS server", e);
143 }
144 }
145
146 @Override
147 public void handlePacketFromServer(PacketContext context) {
148 InboundPacket pkt = context.inPacket();
149 Ethernet ethPkt = pkt.parsed();
150
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400151 log.debug("Skipping Ethernet packet type {}",
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100152 EthType.EtherType.lookup(ethPkt.getEtherType()));
153 }
154
155 class RadiusListener implements Runnable {
156
157 @Override
158 public void run() {
159 boolean done = false;
160 int packetNumber = 1;
161
162 log.info("UDP listener thread starting up");
163 RADIUS inboundRadiusPacket;
164 while (!done) {
165 try {
166 byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
167 DatagramPacket inboundBasePacket =
168 new DatagramPacket(packetBuffer, packetBuffer.length);
169 DatagramSocket socket = radiusSocket;
170 socket.receive(inboundBasePacket);
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400171 log.debug("Packet #{} received", packetNumber++);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100172 try {
173 inboundRadiusPacket =
174 RADIUS.deserializer()
175 .deserialize(inboundBasePacket.getData(),
176 0,
177 inboundBasePacket.getLength());
178 aaaManager.handleRadiusPacket(inboundRadiusPacket);
179 } catch (DeserializationException dex) {
180 log.error("Cannot deserialize packet", dex);
181 } catch (StateMachineException sme) {
182 log.error("Illegal state machine operation", sme);
183 }
184
185 } catch (IOException e) {
186 log.info("Socket was closed, exiting listener thread");
187 done = true;
188 }
189 }
190 }
191 }
192
193 RadiusListener radiusListener = new RadiusListener();
194}