Perform SNMP walk using SharpSnmpLib BulkWalk method - c#

I am trying to retrieve the MAC address of a device that connects to the network. My goal is to perform a WALK and then search the results by the port number that triggered the event.
I first grab the port information via a GetRequestMessage (Success). Then I TRY to perform a walk to get the MAC Address table. I do not get any errors or exceptions, but I also do not get any results.
Where am I going wrong?
// Capture IPAddress
string ipAddress = e.Sender.Address.ToString();
// Capture the port
string port = e.Message.Scope.Pdu.Variables[0].Data.ToString();
// Setup Authentication with password from App.Config
var auth = new SHA1AuthenticationProvider(new OctetString(_Password));
// Setup Privacy with Phrase from App.Config
var priv = new DESPrivacyProvider(new OctetString(_Phrase), auth);
// Setup username from App.Config
OctetString userName = new OctetString(_Username);
// Create IPEndPoint
IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(ipAddress), 161);
// Create discovery
Discovery discovery = Messenger.GetNextDiscovery(SnmpType.GetRequestPdu);
// Create report
ReportMessage report = discovery.GetResponse(60000, iPEndPoint);
// Setup OID variables to get port information
List<Variable> variables = new List<Variable>
{
// Port Description
new Variable(new ObjectIdentifier($"1.3.6.1.2.1.31.1.1.1.18.{ port }")),
// Port PVID
new Variable(new ObjectIdentifier($"1.3.6.1.2.1.17.7.1.4.5.1.1.{ port }")),
// Voice VLAN
new Variable(new ObjectIdentifier($"1.3.6.1.4.1.674.10895.5000.2.6132.1.1.1.2.13.1.28.{ port }")),
};
// Create SNMP request
GetRequestMessage request = new GetRequestMessage(VersionCode.V3, Messenger.NextMessageId, Messenger.NextRequestId, userName, variables, priv, Messenger.MaxMessageSize, report);
// Send request and get reply
ISnmpMessage reply = request.GetResponse(60000, iPEndPoint);
// Request failed
if (reply.Pdu().ErrorStatus.ToInt32() != 0) // != ErrorCode.NoError
{
throw ErrorException.Create(
"error in response",
IPAddress.Parse(ipAddress),
reply);
}
// Store reply information
string Port_Description = reply.Scope.Pdu.Variables[0].Data.ToString(),
Port_Pvid = reply.Scope.Pdu.Variables[1].Data.ToString(),
Port_VLAN = reply.Scope.Pdu.Variables[2].Data.ToString();
// Create BulkWalk Discovery
// TODO: Do I need to do this or can I reuse the original discovery??
Discovery BULKWALK_discovery = Messenger.GetNextDiscovery(SnmpType.GetRequestPdu);
// Create BulkWalk report
// TODO: Do I need to do this or can I reuse the original report??
ReportMessage BULKWALK_report = BULKWALK_discovery.GetResponse(60000, iPEndPoint);
// Variable to store the results of the WALK
var BULKWALK_results = new List<Variable>();
// Perform the walk and return the count of results. Community name from App.Config
var BULKWALK_results_count = Messenger.BulkWalk(VersionCode.V3, iPEndPoint, new OctetString(_CommunityName), OctetString.Empty, new ObjectIdentifier($"1.3.6.1.2.1.17.7.1.2.2.1.2"), BULKWALK_results, 60000, 10, WalkMode.WithinSubtree, priv, BULKWALK_report);
Debugger.Break();
EDIT
Also, I am using this resource as guidance.

So I found the issue, which was two fold.
The first was when instantiating the Discovery for the BulkWalk, it needs to be as follows:
Discovery discovery = Messenger.GetNextDiscovery(SnmpType.GetBulkRequestPdu);
The key part being getting the SnmpType correct (my code above is SnmpType.GetRequestPdu and not SnmpType.GetBulkRequestPdu). The tutorial does not mention that the SnmpType is different.
Second, when passing parameters into the Messenger.BulkWalk() method I was passing in the community name and not the user name. The source code remarks for the BulkWalk method does say community name but it should be the user.
I did as Lex Li suggested and complied/ran the snmpwalk sample to verify that there were no issues. After that was a success, I went back and reviewed the source code for that sample and found the two issues.

Related

C# - Detect public ip adress change, VPN issue

With following code I am able to track public IP changes of my desktop application. This should be able to track if either the public IP changed or the user enabled a VPN to change his public IP. This code is run on application launch and used once again when a check is needed:
public class PublicIP
{
IPAddress last_ip=null;
DateTime timestamp_lastipchange;
public void UpdateIP()
{
List<string> hosts = new List<string>()
{
"https://api.ipify.org",
"https://ipinfo.io/ip",
"https://checkip.amazonaws.com",
"https://wtfismyip.com/text",
"http://icanhazip.com"
};
using(WebClient webclient = new WebClient())
{
foreach(string host in hosts)
{
//Download each string from hosts until an IP could be fetched
try{
var newip = IPAddress.Parse(webclient.DownloadString(service)); //Downloading the string
if(!newip.IsEqual(last_ip) && last_ip!=null) timestamp_lastipchange = DateTime.Now; //Check if the ip changed, if the last known ip does not exists skipp this step
last_ip = newip; //Save last known ip
return;
}
catch { }
}
}
}
}
This approach seems to work pretty well, however during UnitTesting some workflows do not fetch a new IP:
IP change by switching networks: change gets successfully detected
IP changed by provider: change gets successfully detected
VPN was enabled when the application was launched and is then turned off:
change gets successfully detected
VPN was disabled on application start and is turned on during runtime:
change does not get detected. Webclient.DownloadString() still returns the same IP as if the VPN was not enabled.
I am not really sure what is happening in workflow nr 4. Do I have to manually select the new network interface (VPN)? Or is this a caching problem on the client/server side?
WebClient is high-level and might using static pool behind-the-scene (and also deprecated). You might try using HttpClient instead, because HttpClient handle connection via its message handler, and the default one is not static, which means this should work:
using(var httpClient = new HttpClient())
{
var newip = IPAddress.Parse(webclient.GetStringAsync(service)
.ConfigureAwait(false).GetAwaiter().GetResult());
// ...
}

How to get the assigned port of a GrpcServer

I want to create a gRPC server and bind it to a random port.
The documentation states that port 0 (ServerPort.PickUnused = 0) can be passed to achieve this:
var server = new Server
{
Ports = { new ServerPort("0.0.0.0", ServerPort.PickUnused, ServerCredentials.Insecure) }
};
// ... adding some services
server.Start();
How can I determine which port has been assigned to the server?
The passed ServerPort still mentions 0:
var enumerator = server.Ports.GetEnumerator();
enumerator.MoveNext();
var serverPort = enumerator.Current as ServerPort;
Debug.Log($"RPC Server started on port {serverPort.Port}");
// Out: RPC Server started on port 0
Sometimes reading the WHOLE documentation page BEFORE googling around would save so much time.
ServerPort has a property named BoundPort (quote: "The port actually bound by the server.
This is useful if you let server pick port automatically.")
This returns the actual port:
Debug.Log($"RPC Server started on port {serverPort.BoundPort}");

Is there an MQ/XMS equivalent for the MQ/JMS setTargetClient

I have a XMS publish app, that is working, but it is including JMS headers as part of the message. My subscribe app is actually a python app, and I was wondering if it is possible to remove the JMS headers from the XMS app. I know it is possible in JMS, but is it possible in C# / XMS.
My C# code is fairly simple (with some of the details left out -
// Get an instance of factory.
factoryFactory = XMSFactoryFactory.GetInstance(XMSC.CT_WMQ);
// Create WMQ Connection Factory.
cf = factoryFactory.CreateConnectionFactory();
// Set the properties
cf.SetStringProperty(XMSC.WMQ_HOST_NAME, conn.host);
...
// Create connection.
connectionWMQ = cf.CreateConnection();
// Create session
sessionWMQ = connectionWMQ.CreateSession(false, AcknowledgeMode.AutoAcknowledge);
// Create destination
destination = sessionWMQ.CreateTopic(conn.topic_name);
// Create producer
producer = sessionWMQ.CreateProducer(destination);
// Start the connection to receive messages.
connectionWMQ.Start();
// Create a text message and send it.
textMessage = sessionWMQ.CreateTextMessage();
textMessage.Text = xmsJson.toJsonString();
producer.Send(textMessage);
In MQ /JMS I can use setTargetClient to remove the JMS headers -
private void setToNoJMSHeaders(Destination destination) {
try {
MQDestination mqDestination = (MQDestination) destination;
mqDestination.setTargetClient(WMQConstants.WMQ_CLIENT_NONJMS_MQ);
} catch (JMSException jmsex) {
logger.warning("Unable to set target destination to non JMS");
}
}
I was wondering if I can do the same to the topic destination in XMS
// Create destination
destination = sessionWMQ.CreateTopic(conn.topic_name);
// Configure the destination to Non-JMS
... ???
Yes, you should be able to do this
Try
// Create destination
destination = sessionWMQ.CreateTopic(conn.topic_name);
destination.SetIntProperty(XMSC.WMQ_TARGET_CLIENT, XMSC.WMQ_TARGET_DEST_MQ);
See: https://www.ibm.com/support/knowledgecenter/en/SSFKSJ_9.1.0/com.ibm.mq.ref.dev.doc/prx_wmq_target_client.htm

How to use tcplistener and tcpclient on device and computer with different ip in same Network?

I'm trying to communicate with a modbus device in my network at ip 192.168.1.76. My host computer address is 192.168.1.132. I'm not able to connect to or listen to device ip.
basically i'm using NModbus4 library. I've created a ModbusTCPSlave and attached the tcp listener to it. then i assigned ModbusSlaveRequestReceived event to that slave. but it gives nothing in return when i try to change register values directly from Modscan software.
Main()
{
var masterEndpoint = new IPEndPoint(IPAddress.Parse("192.168.1.132"), 502);
var listener = new TcpListener(IPAddress.Any, 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, new TcpListener(masterEndpoint), 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();
}
private static void Modbus_Request_Event(object sender, Modbus.Device.ModbusSlaveRequestEventArgs e)
{
//disassemble packet from master
byte fc = e.Message.FunctionCode;
byte[] data = e.Message.MessageFrame;
byte[] byteStartAddress = new byte[] { data[3], data[2] };
byte[] byteNum = new byte[] { data[5], data[4] };
Int16 StartAddress = BitConverter.ToInt16(byteStartAddress, 0);
Int16 NumOfPoint = BitConverter.ToInt16(byteNum, 0);
Console.WriteLine(fc.ToString() + "," + StartAddress.ToString() + "," + NumOfPoint.ToString());
}
I expect to get function code, start address and number of points in console application when any register value is changed
I copied your code. Changed the IP address to my "server" and it worked.
So, the issue you are having is either in the setup of your "server" or in the PLC program.
I thought that I had to do some port forwarding on my router. I did not. It did not make a difference.
Server setup:
Your "server"'s IP address needs to be static. Whether your 'server' is your development system or not. And don't forget when you deploy... Server's IP address has to be static as well (not that it wouldn't be...just saying)
Add an inbound Firewall rule to allow connections to the port, in this case 502, otherwise you'll have to allow access every time you launch/start a test.
PLC program
I am using Click PLC's by Koyo. Not sure if this is the rule for all PLC's or not; but, we had to add a line of code to "write" the values we wanted to pick up off the TCP stream. Without the write, the PLC was not sending out a request to join the TcpListener.
Last:
The code to start your listener only needs to be this:
var listener = new TcpListener(IPAddress.Parse("192.168.1.244"), 502);
listener.Start();
var slave = ModbusTcpSlave.CreateTcp(255, listener, 10);
slave.ModbusSlaveRequestReceived += Modbus_Request_Event;
slave.Listen();

How to connect to wifi using simple wifi in wpf?

I am trying to connect to wifi using simplewifi. Currently, I have tried:
Wifi wifi = new Wifi();
// get list of access points
IEnumerable<AccessPoint> accessPoints = wifi.GetAccessPoints();
// for each access point from the list
foreach (AccessPoint ap in accessPoints)
{
Console.WriteLine("ap: {0}\r\n", ap.Name);
//check if SSID is desired
if (ap.Name.StartsWith("z"))
{
//verify connection to desired SSID
Console.WriteLine("connected: {0}, password needed: {1}, has profile: {2}\r\n", ap.Name, ap.IsConnected, ap.HasProfile);
if (!ap.IsConnected)
{
//connect if not connected
Console.WriteLine("\r\n{0}\r\n", ap.ToString());
Console.WriteLine("Trying to connect..\r\n");
AuthRequest authRequest = new AuthRequest(ap);
authRequest.Password = "123456789";
var x=ap.Connect(authRequest);
}
}
}
Here I am not able to pass the password if I have the password hardcoded like
var password="abc123"
How can I pass the password and connect?
Also, the connect method always returns false, even if I have to connect to a wifi with no password.
You need to set authRequest.Password = "yourpassword";
before your ap.connect(authRequest);
Add in following console.write() from https://github.com/DigiExam/simplewifi
Place at the top of your file
using SimpleWifi;
Then in your function
// Wifi object
Wifi wifi = new Wifi();
// get list of access points
IEnumerable<AccessPoint> accessPoints = wifi.GetAccessPoints();
// for each access point from list
foreach (AccessPoint ap in accessPoints){
Console.WriteLine("ap: {0}\r\n", ap.Name);
//check if SSID is desired
if (ap.Name.StartsWith("ardrone_")){
//verify connection to desired SSID
Console.WriteLine("connected: {0}, password needed: {1}, has profile: {2}\r\n", ap.Name, ap.IsConnected, ap.HasProfile);
if (!ap.IsConnected){
//connect if not connected
Console.WriteLine("\r\n{0}\r\n", ap.ToString());
Console.WriteLine("Trying to connect..\r\n");
AuthRequest authRequest = new AuthRequest(ap);
ap.Connect(authRequest);
}
}
}
Adding overwriteProfile set to "true" to parameters of the AccessPoint.Connect method solved the problem for me.
F# example:
open SimpleWifi
[<EntryPoint>]
let main argv =
let wifi = Wifi()
let accessPoint = wifi.GetAccessPoints()
|> Seq.find (fun (i:AccessPoint) -> i.Name = "Tpkl6" )
let try1 = accessPoint.Connect( AuthRequest(accessPoint, Password="12345678"), true )
let try2 = accessPoint.Connect( AuthRequest(accessPoint, Password="markvirchenko20"), true )
printfn "%b\n%b" try1 try2
0 // return an integer exit code
By the way, you asked about ispasswordvalid function in the comments:
I disconnected all internet and tried to connect, ispasswordvalid verification gives true, but while connecting it fails
ispasswordvalid doesn't actually check if the password is correct i.e matching the one set on the wifi. It simply checks if the password has a valid structure, e.g at least 8 symbols length.

Categories

Resources