Настройка разбора опции DHCP Option 82
Перед прочтением данной главы рекомендуется к прочтению глава Процессор ru.bitel.bgbilling.modules.inet.dhcp.InetDhcpProcessor.
Извлечение значений, идентифицирующих абонента из DHCP-пакета
Cisco ISG и SmartEdge и разные типы устройств c разным форматом agentRemoteId
Извлечение значений, идентифицирующих абонента из 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
) );
}
}
}
Если же giaddr в DHCP-пакете relay agent'а, от которого получил запрос Cisco/SmartEdge, то для типа устройства relay agent'а нужно указать отдельный обработчик, см. выше .