Настройка разбора опции DHCP.82
Материал из BiTel WiKi
Содержание |
Извлечение значений, идентифицирующих абонента из DHCP-пакета
Для корректной работы нужно правильно извлекать значения agentRemoteId, circuitId (port/VLAN) из DHCP-пакета. А в случае использования IPoE c Cisco ISG или SmartEdge еще и из RADIUS-пакетов (в этом случае субопции опции 82 находятся внутри пакетов).
# Нужно указать код субопции опции 82 для извлечения значений # agentRemoteId обычно находится в субопции 2 dhcp.option82.agentRemoteId.code=2 # interfaceId обычно находится в субопции 1 (circuitId) dhcp.option82.interfaceId.code=1 # vlanId обычно находится в субопции 1 (circuitId) dhcp.option82.vlanId.code=1
# Если в субопции отсутствует заголовок с длиной субопции, то укажите 0. Иначе укажите длину заголовка. # Данный параметр используется в том числе, для того, чтобы извлеченные значения circuitId из DHCP-пакета и из RADIUS-пакета были идентичны. # Соответственно, значение position нужно указывать относительно removeHeader. dhcp.option82.removeHeader=0
# Нужно указать параметры извлечения agentRemoteId из субопции (dhcp.option82.agentRemoteId.code) # позиция значения внутри субопции dhcp.option82.agentRemoteId.position=2 # если длина значения может изменятся и нужно брать значение до конца субопции, то укажите -1 dhcp.option82.agentRemoteId.length=6 # 0, если remoteId в бинарном виде, например, MAC-адрес; 1, если там закодирована строка dhcp.option82.agentRemoteId.type=0
# Нужно указать параметры извлечения interfaceId из субопции (dhcp.option82.interfaceId.code) dhcp.option82.interfaceId.position=5 dhcp.option82.interfaceId.length=1
# Нужно указать параметры извлечения interfaceId из субопции (dhcp.option82.vlanId.code) dhcp.option82.vlanId.position=2 dhcp.option82.vlanId.length=2
Разные типы устройств
Если используются разные типы устройств, у которых разные форматы circuitId, тип поиска DHCP-устройства должен быть 0 (в этом режиме сначала находится устройство по giaddr, у него вызывается preprocess, затем находится агентское ус-во, у него тоже вызывается preprocess) или 1 (в этом режиме сначала находится устройство по giaddr, затем находится агентское ус-во, у него тоже вызывается preprocess).
dhcp.deviceSearchMode=0
Конфигурация парсинга agentRemoteId должна быть указана в устройстве, с которого приходит запрос на InetAccess (т.е. чей giaddr указан в пакете). А конфигурация извлечения порта/VLAN из curcuitId должна быть указана в агентских типах устройствах. Таким образом InetAccess найдет relay agent по giaddr, по его конфигурации извлечет agentRemoteId, по agentRemoteId найдет дочернее агентское устройство и уже по его конфигурации извлечет значения порта/VLAN.
Разные типы устройств c разным форматом agentRemoteId
В этом случае нельзя однозначно указать в конфигурации как извлечь agentRemoteId, в отличие от варианта выше. Поэтому нужно воспользоваться предобработкой пакетов. Укажите тип поиска DHCP-устройства = 0 (в этом режиме сначала находится устройство по giaddr, у него вызывается preprocess, затем находится агентское ус-во, у него тоже вызывается preprocess).
dhcp.deviceSearchMode=0
Расширьте обработчик процессора протокола типа устройства, с с которого приходит запрос на InetAccess (т.е. чей giaddr указан в пакете). По giaddr InetAccess однозначно найдет устройство. Затем вызовет у него предобработку, в которой нужно определить как распарсить и в ручную проставить agentRemoteId.
import java.util.Arrays; import ru.bitel.bgbilling.kernel.network.dhcp.DhcpPacket; import ru.bitel.bgbilling.kernel.network.dhcp.DhcpProtocolHandler; import ru.bitel.bgbilling.modules.inet.access.sa.ProtocolHandlerAdapter; import ru.bitel.bgbilling.modules.inet.dhcp.InetDhcpProcessor; public class Dhcp82ProtocolHandler extends ProtocolHandlerAdapter implements DhcpProtocolHandler { @Override public void preprocessDhcpRequest( DhcpPacket request, DhcpPacket response ) throws Exception { byte[] agentRemoteId = request.getSubOption( (byte)2 ).value; // DLink if( agentRemoteId.length == 8 ) { request.setOption( InetDhcpProcessor.AGENT_REMOTE_ID, Arrays.copyOfRange( agentRemoteId, 2, 6 ) ); } else { request.setOption( InetDhcpProcessor.AGENT_REMOTE_ID, Arrays.copyOfRange( agentRemoteId, 5, 6 ) ); } } }
Конфигурация извлечения порта/VLAN из curcuitId должна быть указана в агентских типах устройствах. Таким образом InetAccess найдет relay agent по giaddr, предобработка извлечет и проставит agentRemoteId, по agentRemoteId InetAccess найдет дочернее агентское устройство и уже по его конфигурации извлечет значения порта/VLAN.
Cisco ISG и SmartEdge
В отличие от схемы DHCP82 без Cisco ISG/SmartEdge, здесь еще нужно извлечь remoteId и circuitId из RADIUS-пакета.
# Если в значении атрибута отсутствует заголовок с длиной субопции, то укажите 0. Иначе укажите длину заголовка. # Данный параметр используется в том числе, для того, чтобы извлеченные значения circuitId из DHCP-пакета и из RADIUS-пакета были идентичны. # Соответственно, значение position нужно указывать относительно removeHeader. radius.agent.option.removeHeader=2
# SmartEdge # код атрибута radius.agent.option.remoteId.type=96 # позиция в значении атрибута radius.agent.option.remoteId.position=0 # длина radius.agent.option.remoteId.length=-1 radius.agent.option.circuitId.type=97 # или radius.agent.option.remoteId.type=202 radius.agent.option.remoteId.position=0 radius.agent.option.remoteId.length=-1 radius.agent.option.circuitId.type=202
# Cisco ISG radius.agent.option.remoteId.type=1 radius.agent.option.remoteId.prefix=remote-id-tag= radius.agent.option.circuitId.type=1 radius.agent.option.circuitId.prefix=circuit-id-tag=
Cisco ISG и SmartEdge и разные типы устройств c разным форматом agentRemoteId
В этом случае нельзя однозначно указать в конфигурации как извлечь agentRemoteId и curcuitId из RADIUS-пакета. Поэтому это нужно сделать в предобработке (извлечение из RADIUS-пакета и сейчас происходит в предобработке, но согласно конфигурации - это можно увидеть в динамических классах ISGProtocolHandler и SmartEdgeClipsProtocolHandler). Расширьте класс предобработки Cisco ISG/SmartEdge:
import java.util.Arrays; import ru.bitel.bgbilling.kernel.network.radius.RadiusAttribute; import ru.bitel.bgbilling.kernel.network.radius.RadiusPacket; import ru.bitel.bgbilling.modules.inet.radius.InetRadiusProcessor; public class XSmartEdgeClipsProtocolHandler extends SmartEdgeClipsProtocolHandler { @Override protected void setAgentOptions( RadiusPacket request ) { RadiusAttribute<byte[]> agentRemoteIdAttribute = request.getAttribute( 2352, 96 ); RadiusAttribute<byte[]> circuitRemoteIdAttribute = request.getAttribute( 2352, 97 ); byte[] agentRemoteId = agentRemoteIdAttribute.getValue(); byte[] circuitRemoteId = circuitRemoteIdAttribute.getValue(); // DLink if( agentRemoteId.length == 8 ) { request.setOption( InetRadiusProcessor.AGENT_REMOTE_ID, Arrays.copyOfRange( agentRemoteId, 2, 6 ) ); request.setOption( InetRadiusProcessor.AGENT_CIRCUIT_ID, Arrays.copyOfRange( circuitRemoteId, 2, circuitRemoteId.length - 2 ) ); } else { request.setOption( InetRadiusProcessor.AGENT_REMOTE_ID, Arrays.copyOfRange( agentRemoteId, 5, 6 ) ); request.setOption( InetRadiusProcessor.AGENT_CIRCUIT_ID, Arrays.copyOfRange( circuitRemoteId, 2, circuitRemoteId.length - 2 ) ); } } }
Если в DHCP-пакете указан giaddr Cisco/SmartEdge, то в этот класс нужно добавить предобработку DHCP
import java.util.Arrays; import ru.bitel.bgbilling.kernel.network.dhcp.DhcpPacket; import ru.bitel.bgbilling.kernel.network.radius.RadiusAttribute; import ru.bitel.bgbilling.kernel.network.radius.RadiusPacket; import ru.bitel.bgbilling.modules.inet.dhcp.InetDhcpProcessor; import ru.bitel.bgbilling.modules.inet.radius.InetRadiusProcessor; public class XSmartEdgeClipsProtocolHandler extends SmartEdgeClipsProtocolHandler { @Override protected void setAgentOptions( RadiusPacket request ) { RadiusAttribute<byte[]> agentRemoteIdAttribute = request.getAttribute( 2352, 96 ); RadiusAttribute<byte[]> circuitRemoteIdAttribute = request.getAttribute( 2352, 97 ); byte[] agentRemoteId = agentRemoteIdAttribute.getValue(); byte[] circuitRemoteId = circuitRemoteIdAttribute.getValue(); // DLink if( agentRemoteId.length == 8 ) { request.setOption( InetRadiusProcessor.AGENT_REMOTE_ID, Arrays.copyOfRange( agentRemoteId, 2, 6 ) ); request.setOption( InetRadiusProcessor.AGENT_CIRCUIT_ID, Arrays.copyOfRange( circuitRemoteId, 2, circuitRemoteId.length - 2 ) ); } else { request.setOption( InetRadiusProcessor.AGENT_REMOTE_ID, Arrays.copyOfRange( agentRemoteId, 5, 6 ) ); request.setOption( InetRadiusProcessor.AGENT_CIRCUIT_ID, Arrays.copyOfRange( circuitRemoteId, 2, circuitRemoteId.length - 2 ) ); } } @Override public void preprocessDhcpRequest( DhcpPacket request, DhcpPacket response ) throws Exception { byte[] agentRemoteId = request.getSubOption( (byte)2 ).value; // DLink if( agentRemoteId.length == 8 ) { request.setOption( InetDhcpProcessor.AGENT_REMOTE_ID, Arrays.copyOfRange( agentRemoteId, 2, 6 ) ); } else { request.setOption( InetDhcpProcessor.AGENT_REMOTE_ID, Arrays.copyOfRange( agentRemoteId, 5, 6 ) ); } } }