I am looking into address.c mainly address_add() and address_remove_oldest() functions.
Unless I am mistaken this is what happens (my code is similar to bacrd example):
When the driver starts the "to be bound" entries in address cache are marked as BAC_ADDR_BIND_REQ.
When I-am is received via h_iam.c then in address_add() the previously set BAC_ADDR_BIND_REQ flag is reset.
The entry continues its life as BAC_ADDR_IN_USE, given BAC_ADDR_LONG_TIME.
What is worse is that opportunistic I-am's entries being received second time are also given long time.
So all address cache entries end up the same. (BAC_ADDR_IN_USE and BAC_ADDR_LONG_TIME)
On this site I observed I-am attack from about 1700 devices.
I guess this could be triggered by someone trying to use a bacnet explorer.
I believe this can push my prefered entries away from address cache causing no comms being send out.
As far as I can see entries in address cache for addresses that the driver needs to talk to, need to be protected.
Does this sound right?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Hi Steve,
I have made changes to address.c, when I know what I have done works, I will post the code with description.
So far it looks my colleague will go to site next week at some point, but it may take longer.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
1) Top Protected Entry
entries from 0 to Top_Protected_Entry are not removed by address_remove_oldest()function.
when I-am attack occurs only entries between Top_Protected_Entry and MAX_ADDRESS_CACHE can be removed.
I do the following from my main:
ReadConfigFromFile(); which also gives me num of "to be bound devices"
address_init();
address_protected_entry_index_set(BacnetData->NumDevices);
address_own_device_id_set(BacnetData->DeviceData.MyDeviceInstance);
2) Own Device ID
If I-am comes from the driver itself it gets ignored.
(This will not work if device object id gets changed from bacnet!, I disabled changing device object id from bacnet in my code)
3)
I edited address_bind_request() and address_get_by_index() to also return remaining ttl.
(So I can bind them again maybe 5 mins before their TTL expires.
1) removes my problem, 2) and 3) are really for convenience
Please feel free to include my changes to bacnet stack if you think they are useful.
If you did so,lots of the example main.c would need to be changed too.
Hi Steve,
address.c (attched)
buffer overflow is detected and handled (program was crashing for 255 entries in address cache, apdu len would be about 3k)
device-client.c (attached)
a) shows how the address_list_encode function is called
b) I copied code from device.c for read range because I noticed baceye (http://www.baceye.com, demo free) after getting abort for device address binding then switches to read range and I can see all 255 entries.
YABE doesn't do this.
Is what baceye does correct?
Hi,
I am looking into address.c mainly address_add() and address_remove_oldest() functions.
Unless I am mistaken this is what happens (my code is similar to bacrd example):
When the driver starts the "to be bound" entries in address cache are marked as BAC_ADDR_BIND_REQ.
When I-am is received via h_iam.c then in address_add() the previously set BAC_ADDR_BIND_REQ flag is reset.
The entry continues its life as BAC_ADDR_IN_USE, given BAC_ADDR_LONG_TIME.
What is worse is that opportunistic I-am's entries being received second time are also given long time.
So all address cache entries end up the same. (BAC_ADDR_IN_USE and BAC_ADDR_LONG_TIME)
On this site I observed I-am attack from about 1700 devices.
I guess this could be triggered by someone trying to use a bacnet explorer.
I believe this can push my prefered entries away from address cache causing no comms being send out.
As far as I can see entries in address cache for addresses that the driver needs to talk to, need to be protected.
Does this sound right?
Yes, your observation and suggestion for protection sounds right. Any ideas to fix it?
I've often employed a filter of I-Am based on a list of Vendor ID that my device had configured, but that is really just a bandaid.
Hi Steve,
I have made changes to address.c, when I know what I have done works, I will post the code with description.
So far it looks my colleague will go to site next week at some point, but it may take longer.
Hi Steve,
I have made 3 changes to address.c
1) Top Protected Entry
entries from 0 to Top_Protected_Entry are not removed by address_remove_oldest()function.
when I-am attack occurs only entries between Top_Protected_Entry and MAX_ADDRESS_CACHE can be removed.
I do the following from my main:
ReadConfigFromFile(); which also gives me num of "to be bound devices"
address_init();
address_protected_entry_index_set(BacnetData->NumDevices);
address_own_device_id_set(BacnetData->DeviceData.MyDeviceInstance);
2) Own Device ID
If I-am comes from the driver itself it gets ignored.
(This will not work if device object id gets changed from bacnet!, I disabled changing device object id from bacnet in my code)
3)
I edited address_bind_request() and address_get_by_index() to also return remaining ttl.
(So I can bind them again maybe 5 mins before their TTL expires.
1) removes my problem, 2) and 3) are really for convenience
Please feel free to include my changes to bacnet stack if you think they are useful.
If you did so,lots of the example main.c would need to be changed too.
address.c attached,
Thank you Miroslav
I ported your enhancements to trunk/bacnet-stack/
https://sourceforge.net/p/bacnet/code/3027/
and 0.8.x branch.
https://sourceforge.net/p/bacnet/code/3028/
Note that the changes for 3) would break API so I just made new function names for them.
Hi Steve,
address.c (attched)
buffer overflow is detected and handled (program was crashing for 255 entries in address cache, apdu len would be about 3k)
device-client.c (attached)
a) shows how the address_list_encode function is called
b) I copied code from device.c for read range because I noticed baceye (http://www.baceye.com, demo free) after getting abort for device address binding then switches to read range and I can see all 255 entries.
YABE doesn't do this.
Is what baceye does correct?
into my main.c I have copied read range handler
sorry, now attaching device client