blob: 32d4f21806711a88ced3931154741cdcb26e16de [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 */
Matteo Scandolocf847b82019-04-26 15:00:00 -070016package org.opencord.aaa.impl;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010017
Saurav Das987441a2018-09-18 16:33:47 -070018import static org.onosproject.net.packet.PacketPriority.CONTROL;
19import static org.slf4j.LoggerFactory.getLogger;
20
21import java.io.IOException;
22import java.net.DatagramPacket;
23import java.net.DatagramSocket;
24import java.net.InetAddress;
25import java.net.InetSocketAddress;
26import java.net.UnknownHostException;
27import java.util.concurrent.ExecutorService;
28import java.util.concurrent.Executors;
29
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010030import org.onlab.packet.DeserializationException;
31import org.onlab.packet.EthType;
32import org.onlab.packet.Ethernet;
33import org.onlab.packet.RADIUS;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010034import org.onosproject.core.ApplicationId;
35import org.onosproject.net.flow.DefaultTrafficSelector;
36import org.onosproject.net.flow.TrafficSelector;
37import org.onosproject.net.packet.InboundPacket;
38import org.onosproject.net.packet.PacketContext;
39import org.onosproject.net.packet.PacketService;
Matteo Scandolocf847b82019-04-26 15:00:00 -070040import org.opencord.aaa.AaaConfig;
41import org.opencord.aaa.RadiusCommunicator;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010042import org.slf4j.Logger;
43
Saurav Das987441a2018-09-18 16:33:47 -070044import com.google.common.util.concurrent.ThreadFactoryBuilder;
Jonathan Hartf935b122018-07-11 16:16:02 -070045
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010046/**
47 * Handles Socket based communication with the RADIUS server.
48 */
49public class SocketBasedRadiusCommunicator implements RadiusCommunicator {
50
51 // for verbose output
52 private final Logger log = getLogger(getClass());
53
54 // our unique identifier
55 private ApplicationId appId;
56
57 // to receive Packet-in events that we'll respond to
58 PacketService packetService;
59
60 // Socket used for UDP communications with RADIUS server
61 private DatagramSocket radiusSocket;
62
Jonathan Hartf935b122018-07-11 16:16:02 -070063 private String radiusHost;
64
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010065 // Parsed RADIUS server addresses
66 protected InetAddress radiusIpAddress;
67
68 // RADIUS server TCP port number
69 protected short radiusServerPort;
70
71 // Executor for RADIUS communication thread
72 private ExecutorService executor;
73
74 AaaManager aaaManager;
75
76 SocketBasedRadiusCommunicator(ApplicationId appId, PacketService pktService,
77 AaaManager aaaManager) {
78 this.appId = appId;
79 this.packetService = pktService;
80 this.aaaManager = aaaManager;
81 }
82
83 @Override
84 public void initializeLocalState(AaaConfig newCfg) {
85 if (newCfg.radiusIp() != null) {
86 radiusIpAddress = newCfg.radiusIp();
87 }
88 radiusServerPort = newCfg.radiusServerUdpPort();
Jonathan Hartf935b122018-07-11 16:16:02 -070089 radiusHost = newCfg.radiusHostName();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010090
91 try {
92 radiusSocket = new DatagramSocket(null);
93 radiusSocket.setReuseAddress(true);
94 radiusSocket.bind(new InetSocketAddress(radiusServerPort));
95 } catch (Exception ex) {
96 log.error("Can't open RADIUS socket", ex);
97 }
98
Matt Jeanneret2ff1a782018-06-13 15:24:25 -040099 log.info("Remote RADIUS Server: {}:{}", radiusIpAddress, radiusServerPort);
100
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100101 executor = Executors.newSingleThreadExecutor(
102 new ThreadFactoryBuilder()
103 .setNameFormat("AAA-radius-%d").build());
104 executor.execute(radiusListener);
105 }
106
107 @Override
108 public void clearLocalState() {
109 radiusSocket.close();
110 executor.shutdownNow();
111 }
112
113 @Override
Deepa Vaddireddyd87f2872017-10-24 07:58:11 +0000114 public void deactivate() {
115 clearLocalState();
116 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100117
118 @Override
119 public void requestIntercepts() {
120 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
121 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
122 packetService.requestPackets(selector.build(), CONTROL, appId);
123 }
124
125 @Override
126 public void withdrawIntercepts() {
127 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
128 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
129 packetService.cancelPackets(selector.build(), CONTROL, appId);
130 }
131
132 @Override
133 public void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
134 try {
135 final byte[] data = radiusPacket.serialize();
136 final DatagramSocket socket = radiusSocket;
137
Jonathan Hartf935b122018-07-11 16:16:02 -0700138 try {
139 InetAddress address;
140 if (radiusHost != null) {
141 address = InetAddress.getByName(radiusHost);
142 } else {
143 address = radiusIpAddress;
144 }
145 DatagramPacket packet =
146 new DatagramPacket(data, data.length, address, radiusServerPort);
Saurav Das987441a2018-09-18 16:33:47 -0700147 if (log.isTraceEnabled()) {
148 log.trace("Sending packet {} to Radius Server {}:{} using socket",
149 radiusPacket, address, radiusServerPort);
150 }
Jonathan Hartf935b122018-07-11 16:16:02 -0700151 socket.send(packet);
Shubham Sharma048cc262019-06-19 14:18:50 +0000152 aaaManager.radiusOperationalStatusService.setStatusServerReqSent(true);
Jonathan Hartf935b122018-07-11 16:16:02 -0700153 } catch (UnknownHostException uhe) {
154 log.warn("Unable to resolve host {}", radiusHost);
Shubham Sharma048cc262019-06-19 14:18:50 +0000155 aaaManager.radiusOperationalStatusService.setStatusServerReqSent(false);
Jonathan Hartf935b122018-07-11 16:16:02 -0700156 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100157 } catch (IOException e) {
158 log.info("Cannot send packet to RADIUS server", e);
159 }
160 }
161
162 @Override
163 public void handlePacketFromServer(PacketContext context) {
164 InboundPacket pkt = context.inPacket();
165 Ethernet ethPkt = pkt.parsed();
Saurav Das987441a2018-09-18 16:33:47 -0700166 if (log.isTraceEnabled() && ethPkt.getEtherType() != Ethernet.TYPE_LLDP
167 && ethPkt.getEtherType() != Ethernet.TYPE_BSN) {
168 log.trace("Skipping Ethernet packet type {}",
169 EthType.EtherType.lookup(ethPkt.getEtherType()));
170 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100171 }
172
173 class RadiusListener implements Runnable {
174
175 @Override
176 public void run() {
177 boolean done = false;
178 int packetNumber = 1;
179
180 log.info("UDP listener thread starting up");
181 RADIUS inboundRadiusPacket;
182 while (!done) {
183 try {
184 byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
185 DatagramPacket inboundBasePacket =
186 new DatagramPacket(packetBuffer, packetBuffer.length);
187 DatagramSocket socket = radiusSocket;
188 socket.receive(inboundBasePacket);
kartikey dubeye1545422019-05-22 12:53:45 +0000189 aaaManager.checkForPacketFromUnknownServer(inboundBasePacket.getAddress().getHostAddress());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400190 log.debug("Packet #{} received", packetNumber++);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100191 try {
192 inboundRadiusPacket =
193 RADIUS.deserializer()
194 .deserialize(inboundBasePacket.getData(),
195 0,
196 inboundBasePacket.getLength());
kartikey dubeye1545422019-05-22 12:53:45 +0000197 aaaManager.aaaStatisticsManager.handleRoundtripTime(inboundRadiusPacket.getIdentifier());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100198 aaaManager.handleRadiusPacket(inboundRadiusPacket);
199 } catch (DeserializationException dex) {
kartikey dubeye1545422019-05-22 12:53:45 +0000200 aaaManager.aaaStatisticsManager.getAaaStats().increaseMalformedResponsesRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100201 log.error("Cannot deserialize packet", dex);
202 } catch (StateMachineException sme) {
203 log.error("Illegal state machine operation", sme);
204 }
205
206 } catch (IOException e) {
207 log.info("Socket was closed, exiting listener thread");
208 done = true;
209 }
210 }
211 }
212 }
213
214 RadiusListener radiusListener = new RadiusListener();
215}