blob: 99c9396dd443031771703a9037392b19642f9c97 [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
Shubham Sharma4900ce62019-06-19 14:18:50 +000018import com.google.common.util.concurrent.ThreadFactoryBuilder;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010019import org.onlab.packet.DeserializationException;
20import org.onlab.packet.EthType;
21import org.onlab.packet.Ethernet;
22import org.onlab.packet.RADIUS;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010023import 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;
Matteo Scandolocf847b82019-04-26 15:00:00 -070029import org.opencord.aaa.AaaConfig;
30import org.opencord.aaa.RadiusCommunicator;
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010031import org.slf4j.Logger;
32
Shubham Sharma4900ce62019-06-19 14:18:50 +000033import java.io.IOException;
34import java.net.DatagramPacket;
35import java.net.DatagramSocket;
36import java.net.InetAddress;
37import java.net.InetSocketAddress;
38import java.net.UnknownHostException;
39import java.util.concurrent.ExecutorService;
40import java.util.concurrent.Executors;
41
42import static org.onosproject.net.packet.PacketPriority.CONTROL;
43import static org.slf4j.LoggerFactory.getLogger;
Jonathan Hartf935b122018-07-11 16:16:02 -070044
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010045/**
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
Jonathan Hartf935b122018-07-11 16:16:02 -070062 private String radiusHost;
63
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010064 // Parsed RADIUS server addresses
65 protected InetAddress radiusIpAddress;
66
67 // RADIUS server TCP port number
68 protected short radiusServerPort;
69
70 // Executor for RADIUS communication thread
71 private ExecutorService executor;
72
73 AaaManager aaaManager;
74
75 SocketBasedRadiusCommunicator(ApplicationId appId, PacketService pktService,
76 AaaManager aaaManager) {
77 this.appId = appId;
78 this.packetService = pktService;
79 this.aaaManager = aaaManager;
80 }
81
82 @Override
83 public void initializeLocalState(AaaConfig newCfg) {
84 if (newCfg.radiusIp() != null) {
85 radiusIpAddress = newCfg.radiusIp();
86 }
87 radiusServerPort = newCfg.radiusServerUdpPort();
Jonathan Hartf935b122018-07-11 16:16:02 -070088 radiusHost = newCfg.radiusHostName();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +010089
90 try {
91 radiusSocket = new DatagramSocket(null);
92 radiusSocket.setReuseAddress(true);
93 radiusSocket.bind(new InetSocketAddress(radiusServerPort));
94 } catch (Exception ex) {
95 log.error("Can't open RADIUS socket", ex);
96 }
97
Matt Jeanneret2ff1a782018-06-13 15:24:25 -040098 log.info("Remote RADIUS Server: {}:{}", radiusIpAddress, radiusServerPort);
99
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100100 executor = Executors.newSingleThreadExecutor(
101 new ThreadFactoryBuilder()
102 .setNameFormat("AAA-radius-%d").build());
103 executor.execute(radiusListener);
104 }
105
106 @Override
107 public void clearLocalState() {
108 radiusSocket.close();
109 executor.shutdownNow();
110 }
111
112 @Override
Deepa Vaddireddyd87f2872017-10-24 07:58:11 +0000113 public void deactivate() {
114 clearLocalState();
115 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100116
117 @Override
118 public void requestIntercepts() {
119 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
120 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
121 packetService.requestPackets(selector.build(), CONTROL, appId);
122 }
123
124 @Override
125 public void withdrawIntercepts() {
126 TrafficSelector.Builder selector = DefaultTrafficSelector.builder();
127 selector.matchEthType(EthType.EtherType.EAPOL.ethType().toShort());
128 packetService.cancelPackets(selector.build(), CONTROL, appId);
129 }
130
131 @Override
132 public void sendRadiusPacket(RADIUS radiusPacket, InboundPacket inPkt) {
133 try {
134 final byte[] data = radiusPacket.serialize();
135 final DatagramSocket socket = radiusSocket;
136
Jonathan Hartf935b122018-07-11 16:16:02 -0700137 try {
138 InetAddress address;
139 if (radiusHost != null) {
140 address = InetAddress.getByName(radiusHost);
141 } else {
142 address = radiusIpAddress;
143 }
144 DatagramPacket packet =
145 new DatagramPacket(data, data.length, address, radiusServerPort);
Saurav Das987441a2018-09-18 16:33:47 -0700146 if (log.isTraceEnabled()) {
147 log.trace("Sending packet {} to Radius Server {}:{} using socket",
148 radiusPacket, address, radiusServerPort);
149 }
Jonathan Hartf935b122018-07-11 16:16:02 -0700150 socket.send(packet);
Shubham Sharma4900ce62019-06-19 14:18:50 +0000151 aaaManager.radiusOperationalStatusService.setStatusServerReqSent(true);
Jonathan Hartf935b122018-07-11 16:16:02 -0700152 } catch (UnknownHostException uhe) {
153 log.warn("Unable to resolve host {}", radiusHost);
Shubham Sharma4900ce62019-06-19 14:18:50 +0000154 aaaManager.radiusOperationalStatusService.setStatusServerReqSent(false);
Jonathan Hartf935b122018-07-11 16:16:02 -0700155 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100156 } catch (IOException e) {
157 log.info("Cannot send packet to RADIUS server", e);
158 }
159 }
160
161 @Override
162 public void handlePacketFromServer(PacketContext context) {
163 InboundPacket pkt = context.inPacket();
164 Ethernet ethPkt = pkt.parsed();
Saurav Das987441a2018-09-18 16:33:47 -0700165 if (log.isTraceEnabled() && ethPkt.getEtherType() != Ethernet.TYPE_LLDP
166 && ethPkt.getEtherType() != Ethernet.TYPE_BSN) {
167 log.trace("Skipping Ethernet packet type {}",
168 EthType.EtherType.lookup(ethPkt.getEtherType()));
169 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100170 }
171
172 class RadiusListener implements Runnable {
173
174 @Override
175 public void run() {
176 boolean done = false;
177 int packetNumber = 1;
178
179 log.info("UDP listener thread starting up");
180 RADIUS inboundRadiusPacket;
181 while (!done) {
182 try {
183 byte[] packetBuffer = new byte[RADIUS.RADIUS_MAX_LENGTH];
184 DatagramPacket inboundBasePacket =
185 new DatagramPacket(packetBuffer, packetBuffer.length);
186 DatagramSocket socket = radiusSocket;
187 socket.receive(inboundBasePacket);
kartikey dubeye1545422019-05-22 12:53:45 +0000188 aaaManager.checkForPacketFromUnknownServer(inboundBasePacket.getAddress().getHostAddress());
Matt Jeanneret2ff1a782018-06-13 15:24:25 -0400189 log.debug("Packet #{} received", packetNumber++);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100190 try {
191 inboundRadiusPacket =
192 RADIUS.deserializer()
193 .deserialize(inboundBasePacket.getData(),
194 0,
195 inboundBasePacket.getLength());
kartikey dubeye1545422019-05-22 12:53:45 +0000196 aaaManager.aaaStatisticsManager.handleRoundtripTime(inboundRadiusPacket.getIdentifier());
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100197 aaaManager.handleRadiusPacket(inboundRadiusPacket);
198 } catch (DeserializationException dex) {
kartikey dubeye1545422019-05-22 12:53:45 +0000199 aaaManager.aaaStatisticsManager.getAaaStats().increaseMalformedResponsesRx();
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100200 log.error("Cannot deserialize packet", dex);
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100201 }
Amit Ghoshc9ac1e52017-07-28 12:31:18 +0100202 } catch (IOException e) {
203 log.info("Socket was closed, exiting listener thread");
204 done = true;
205 }
206 }
207 }
208 }
209
210 RadiusListener radiusListener = new RadiusListener();
211}