Having problem connecting to my mqtt broker using CocoaMQTT - ios

I am making one iOS app communicating with Mqtt broker, mainly to publish message. But when I try to connect with broker using CocoaMQTT library it's always giving me error in connection.
I am trying with CocoaMQTT latest version and also 1.1.3 version. But both are failing in connection and giving me error
(Error Domain=kCFStreamErrorDomainNetDB Code=8 "nodename nor servname
provided, or not known" UserInfo={NSLocalizedDescription=nodename nor
servname provided, or not known})
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss.SSS"
let dateString = formatter.string(from: date)
let clientID = "smart-curtain-"+dateString
mqttClient = CocoaMQTT.init(clientID: clientID, host:
contantData.MQTT_BROKER_URL, port: UInt16(1883))
mqttClient.username = nil
mqttClient.password = nil
mqttClient.autoReconnect = true
mqttClient.allowUntrustCACertificate = true
mqttClient.keepAlive = 60
mqttClient.enableSSL = false
So its always ending up withmqttDidDisconnect delegate method. My broker url is tcp://xyz.com (xyz is just example) and port is 1883. I have tried 2-3 Mqtt toll apps from my iPhone to connect with broker detail, but no one able to connect it.
But same settings working fine in Android app. (it is using net.igenius:mqttservice:1.6.4) (this broker is no need authentication)

As shown in the CocoaMQTT doc, the host entry in the init method should be just the hostname, not a URI:
let clientID = "CocoaMQTT-" + String(NSProcessInfo().processIdentifier)
let mqtt = CocoaMQTT(clientID: clientID, host: "localhost", port: 1883)
mqtt.username = "test"
mqtt.password = "public"
mqtt.willMessage = CocoaMQTTWill(topic: "/will", message: "dieout")
mqtt.keepAlive = 60
mqtt.delegate = self
mqtt.connect()
e.g. should be xyz.com not tcp://xyz.com

var session = CocoaMQTT.init(clientID: "user1", host: "xx.xx.xxx.xx", port: 1883)
session.allowUntrustCACertificate = true
No need to send tcp://xx.xx.xxx.xx:port as in android, You can just pass xx.xx.xxx.xx by removing tcp:// and port number separately.

Related

MQTT.Simple Loses Connection to AWS IoT

I have a Raspberry Pi Pico W that I am trying to get to communicate with AWS IoT, and after about 12-24 hours it seems to lose its connection. I have the keep alive set and I can see it's pinging the server. And then it suddenly stops. I'm going to add some code below to show the connection and stuff, but I'm baffled at this point (I am cross-posting this on other Raspberry Pi sites too). Any thoughts on why I can't keep the connection open?
import machine
import time
import ussl as ssl
from robust import MQTTClient
def sub_cb(btopic, bmsg):
global led
led = machine.Pin(15, machine.Pin.OUT)
topic = btopic.decode()
msg = bmsg.decode()
mqtt_message_json = ujson.loads(msg)
if 'desired' in mqtt_message_json['state']:
led_status_update = (mqtt_message_json['state']['desired']['led_status'])
if led.value() != str(led_status_update):
if led_status_update == '0':
print("turning off LED")
led.value(0)
elif led_status_update == '1':
print("turning on LED")
led.value(1)
DeviceID='PicoTestBed03'
PORT=8883
AWS_ENDPOINT={My AWS API End Point}
DISCONNECTED = 0
CONNECTING = 1
CONNECTED = 2
state = DISCONNECTED
KeepAliveSeconds = 60
led = machine.Pin(15, machine.Pin.OUT, value=1)
#Use Websockets
useWebsocket = False
#Create SSL Params object
#Assume the cert, key, and rootCA are all created correctly because my connection is successful
SSL_PARAMS = {'cert': cert, 'key': key, 'server_side': False, "cert_reqs":ssl.CERT_REQUIRED, 'cadata':rootCA}
#Create MQTT Client
client = MQTTClient(DeviceId, AWS_ENDPOINT, port=PORT, keepalive=KeepAliveSeconds, ssl=True, ssl_params=SSL_PARAMS)
#Connect MQTT Client
while state != CONNECTED:
try:
state = CONNECTING
print('AWS TEST: Trying to connect via MQTT...')
client.connect()
state = CONNECTED
except Exception as e:
print('AWS TEST: Could not establish MQTT connection')
continue
print('AWS TEST: MQTT LIVE!')
device_shadow_last_checked = time.localtime()
while 1:
if current_led_status != led.value():
current_led_status = led.value()
device_shadow_update_msg = b'{"state":{"reported":{"led_status":%d}}}' %(led.value())
mqtt_client.publish(led_status_shadow_topic_update, device_shadow_update_msg, qos=0)
if (time.mktime(time.localtime()) - time.mktime(device_shadow_last_checked)) >=60:
client.ping()
device_shadow_last_checked = time.localtime()
client.check_msg()

iOS Packet Tunnel Provider with Local On-Device Server

I'm using the Network Extension framework provided by Apple to build a packet sniffing/monitoring application similar to Charles Proxy and Surge 4 for iOS.
So far, I have the basic structure of the project up and running with the Main Application triggering the PacketTunnelProvider Extension where I can see packets being forwarded via the packetFlow.readPackets(completionHandler:) method. My background isn't in networking so I'm confused on the basic structure of these kinds of apps. Do they host a server on the device that act as the proxy which intercepts network requests? Could anyone provide a diagram of the general flow of the network requests? I.e. what is the relationship between the Packet Tunnel Provider, Proxy Server, Virtual Interface, and Tunnel?
If these apps do use a local on-device server, how do you configure the NEPacketTunnelNetworkSettings to allow for a connection? I have tried incorporating a local on-device server such as GCDWebServer with no luck in establishing a link between the two.
For example, if the GCDWebServer was reachable at 192.168.1.231:8080, how would I change the code below for the client to communicate with the server?
Main App:
let proxyServer = NEProxyServer(address: "192.168.1.231", port: 8080)
let proxySettings = NEProxySettings()
proxySettings.exceptionList = []
proxySettings.httpEnabled = true
proxySettings.httpServer = proxyServer
let providerProtocol = NETunnelProviderProtocol()
providerProtocol.providerBundleIdentifier = self.tunnelBundleId
providerProtocol.serverAddress = "My Server"
providerProtocol.providerConfiguration = [:]
providerProtocol.proxySettings = proxySettings
let newManager = NETunnelProviderManager()
newManager.localizedDescription = "Custom VPN"
newManager.protocolConfiguration = providerProtocol
newManager.isEnabled = true
saveLoadManager()
self.vpnManager = newManager
PacketTunnelProviderExtension:
func startTunnel(options: [String : NSObject]?, completionHandler: #escaping (Error?) -> Void) {
...
let settings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.143")
settings.ipv4Settings = NEIPv4Settings(addresses: ["198.17.203.2"], subnetMasks: ["255.255.255.255"])
settings.ipv4Settings?.includedRoutes = [NEIPv4Route.default()]
settings.ipv4Settings?.excludedRoutes = []
settings.dnsSettings = NEDNSSettings(servers: ["8.8.8.8", "8.8.4.4"])
settings.dnsSettings?.matchDomains = [""]
self.setTunnelNetworkSettings(settings) { error in
if let e = error {
NSLog("Settings error %#", e.localizedDescription)
} else {
completionHandler(error)
self.readPackets()
}
}
...
}
I'm working on the iOS version of Proxyman and my experience can help you:
Do they host a server on the device that acts as the proxy which intercepts network requests?
Yes, you have to start a Listener on the Network Extension (not the main app) to act as a Proxy Server. You can write a simple Proxy Server by using Swift NIO or CocoaAsyncSocket.
To intercept the HTTPS traffic, it's a quite big challenge, but I won't mention here since it's out of the scope.
Could anyone provide a diagram of the general flow of the network requests?
As the Network Extension and the Main app are two different processes, so they couldn't communicate directly like normal apps.
Thus, the flow may look like:
The Internet -> iPhone -> Your Network Extension (VPN) -> Forward to your Local Proxy Server -> Intercept or monitor -> Save to a local database (in Shared Container Group) -> Forward again to the destination server.
From the main app, you can receive the data by reading the local database.
how do you configure the NEPacketTunnelNetworkSettings to allow for a connection?
In the Network extension, let start a Proxy Server at Host:Port, then init the NetworkSetting, like the sample:
private func initTunnelSettings(proxyHost: String, proxyPort: Int) -> NEPacketTunnelNetworkSettings {
let settings: NEPacketTunnelNetworkSettings = NEPacketTunnelNetworkSettings(tunnelRemoteAddress: "127.0.0.1")
/* proxy settings */
let proxySettings: NEProxySettings = NEProxySettings()
proxySettings.httpServer = NEProxyServer(
address: proxyHost,
port: proxyPort
)
proxySettings.httpsServer = NEProxyServer(
address: proxyHost,
port: proxyPort
)
proxySettings.autoProxyConfigurationEnabled = false
proxySettings.httpEnabled = true
proxySettings.httpsEnabled = true
proxySettings.excludeSimpleHostnames = true
proxySettings.exceptionList = [
"192.168.0.0/16",
"10.0.0.0/8",
"172.16.0.0/12",
"127.0.0.1",
"localhost",
"*.local"
]
settings.proxySettings = proxySettings
/* ipv4 settings */
let ipv4Settings: NEIPv4Settings = NEIPv4Settings(
addresses: [settings.tunnelRemoteAddress],
subnetMasks: ["255.255.255.255"]
)
ipv4Settings.includedRoutes = [NEIPv4Route.default()]
ipv4Settings.excludedRoutes = [
NEIPv4Route(destinationAddress: "192.168.0.0", subnetMask: "255.255.0.0"),
NEIPv4Route(destinationAddress: "10.0.0.0", subnetMask: "255.0.0.0"),
NEIPv4Route(destinationAddress: "172.16.0.0", subnetMask: "255.240.0.0")
]
settings.ipv4Settings = ipv4Settings
/* MTU */
settings.mtu = 1500
return settings
}
Then start a VPN,
let networkSettings = initTunnelSettings(proxyHost: ip, proxyPort: port)
// Start
setTunnelNetworkSettings(networkSettings) { // Handle success }
Then forward the package to your local proxy server:
let endpoint = NWHostEndpoint(hostname: proxyIP, port: proxyPort)
self.connection = self.createTCPConnection(to: endpoint, enableTLS: false, tlsParameters: nil, delegate: nil)
packetFlow.readPackets {[weak self] (packets, protocols) in
guard let strongSelf = self else { return }
for packet in packets {
strongSelf.connection.write(packet, completionHandler: { (error) in
})
}
// Repeat
strongSelf.readPackets()
}
From that, your local server can receive the packages then forwarding to the destination server.

Mascapsul MQTT IOS

for the first time I'm developing IOS application for IOT using "MQTT" of framework "Moscapsule"
but, the problem was, I have written connection code as per the frame work but it is not connecting ,here my code
let RandomId : String = "IOS_\(UIDevice.current.identifierForVendor!.uuidString)"
// set MQTT Client Configuration
let mqttConfig = MQTTConfig(clientId: RandomId, host: "http://13.232.153.138", port: 1883, keepAlive: 60)
mqttConfig.mqttAuthOpts = MQTTAuthOpts(username: "byname", password: "password")
let mqttClient = MQTT.newConnection(mqttConfig)
print(mqttClient)
print("MQTT Connection Status : \(String(describing: mqttClient.isConnected))")
print("MQTT is running : \(String(describing: mqttClient.isRunning))")
}
console message was:::
MQTT Connection Status : false

What is proper way to setup auth layer for CouchbaseLite (CBLListener and CBLReplication) for p2p database replication?

I am trying to configure basic login / password authentication for p2p replication.
Replication works fine with no authentication. So I pretty sure my issue relates to authentication configuration.
CBListener configuration:
login = "my_login"
password = "my_password"
listener = CBLListener(manager: CBLManager.sharedInstance(), port: 55555)
listener.setBonjourName(netServiceName, type: netServiceType)
listener.readOnly = true
listener.setPasswords([login : password])
try! listener.start()
CBLReplication configuration:
let netService: NetService = ... // Got from NetServiceBrowserDelegate and NetServiceDelegate
let components = NSURLComponents()
components.scheme = "http"
components.host = netService.hostName
components.port = NSNumber(value: 55555)
components.path = "/" + database.name
components.user = login
components.password = password
let newReplication = database.createPullReplication(components.url!)
newReplication.continuous = true
newReplication.start()
Here is what I am getting in Xcode console:
CBLRestPuller[http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Going online
CBLRestPuller[http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: No local checkpoint; not getting remote one
CBLRestPuller[http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net] Progress: set active = 1
CBLReplication[from http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: active, progress = 0 / 0, err: (null)
nil
CBLRestPuller[http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Reachability state = :reachable (20002), suspended=0
: HTTP auth failed; sent Authorization: Basic bXlfbG9naW46bXlfcGFzc3dvcmQ= ; got WWW-Authenticate: Digest realm="CouchbaseLite", qop="auth", nonce="69773230-683C-4DCC-AB40-A21527A1F911"
CBLSocketChangeTracker[0x127d63810 sg_to_firstfoundry_net]: Can't connect, giving up: CBLHTTP[401, http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_changes?feed=normal&heartbeat=300000&style=all_docs]<--NSURLError[-1013, http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_changes?feed=normal&heartbeat=300000&style=all_docs]
CBLRestPuller[http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: ChangeTracker stopped; error=CBLHTTP[401, http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_changes?feed=normal&heartbeat=300000&style=all_docs]<--NSURLError[-1013, http://my_login:*****#Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_changes?feed=normal&heartbeat=300000&style=all_docs]
I think the most important log here is this line:
: HTTP auth failed; sent Authorization:
Basic bXlfbG9naW46bXlfcGFzc3dvcmQ= ; got WWW-Authenticate: Digest
realm="CouchbaseLite", qop="auth",
nonce="69773230-683C-4DCC-AB40-A21527A1F911"
Alternatively I tried to use CBLAuthenticator instead of injecting login/password into url. Still doesn't work, however I am getting different error messages in log:
What is changed:
// Added:
newReplication.authenticator = CBLAuthenticator.basicAuthenticator(withName: login, password: password)
// Removed:
components.user = login
components.password = password
Here is what I am getting in Xcode console after updating the code:
CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Going online
CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net] Progress: set active = 1
CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Successfully logged in!
RemoteRequest: Added Authorization header for CBLPasswordAuthorizer[my_login/****]
CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]: Starting...
DEALLOC CBLRemoteLogin[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]
2017-02-20 16:51:28.335 Union Dev[1922:1702832] RemoteRequest: CBLRemoteSession starting CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]
Sync: CBLReplication[from http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: active, progress = 0 / 0, err: (null)
nil
CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Reachability state = :reachable (20002), suspended=0
RemoteRequest: Got challenge for CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]: method=NSURLAuthenticationMethodHTTPDigest, err=(null)
RemoteRequest: challenge: (phase 3) continueWithoutCredential
Sync: CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Server is (null)
RemoteRequest: CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]: Got response, status 401
CBLRemoteJSONRequest[GET http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]: Got error CBLHTTP[401, "unauthorized", http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]
Sync: CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net]: Error fetching last sequence: CBLHTTP[401, "unauthorized", http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]
Sync: CBLRestPuller[http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net] Progress: set error = CBLHTTP[401, "unauthorized", http://Uladzimir-Papkos-iPad.local.:55555/sg_to_firstfoundry_net/_local/b3f625c9bddabfb59ee49d78f3bb484a5876b486]
Could anybody point me to place where I am doing something wrong?
After having conversation with Couchbase engineers it was decided that the best solution here is to enable secure http connection, since it doesn't make sense to send login / password through insecure http request.
The easiest (not most secure) way to enable https is to do next:
// Change url to https
components.scheme = "https"
// Inject self-signed generated on the fly certificate into CBLListener
try listener.setAnonymousSSLIdentityWithLabel("use_any_string_here")
More information about configuring https connection for p2p replication is available here.

"Unrecognized SSL message, plaintext connection" during send mail using grails async mail api

I am trying to send mail using Grails Async Mail API
When I tried for Gmail using below configuration :
grails {
mail {
host = "smtp.gmail.com"
port = 465
username = "xxxx#gmail.com"
password = "xxxx"
props = ["mail.smtp.auth":"true",
"mail.smtp.socketFactory.port":"465",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"false"]
}
}
in config.groovy, I was able to send mail. When I changed above configuration for a specific mail server as below :
grails {
mail {
host = "xxx"
port = 25
username = "xxx"
props = ["mail.smtp.auth":"false",
"mail.smtp.socketFactory.port":"25",
"mail.smtp.socketFactory.class":"javax.net.ssl.SSLSocketFactory",
"mail.smtp.socketFactory.fallback":"true",
"mail.smtp.starttls.enable": "false",
"mail.smtp.starttls.required": "false"]
}
}
I am getting below error :
javax.mail.MessagingException: Could not connect to SMTP host: xxx, port: 25;
nested exception is:
javax.net.ssl.SSLException: Unrecognized SSL message, plaintext connection?
Please provide me some hint, what I am doing wrong in above case.
You can try to do simply following and it should work for you
grails {
mail {
host = "xxx"
port = 25
username = "xxx"
props = ["mail.smtp.auth":"false",
"mail.smtp.socketFactory.port":"25",
"mail.smtp.starttls.enable": "true"]
}
}

Resources