Azure cloud service embedded FTP server - c#

I want to host an embedded FTP server inside an Azure cloud service worker role.
To provide passive access to the FTP server, it uses port range 20000-21000.
Inside the ServiceDefinition.csdef I define all needed ports (see screenshot).
The main problem is the huge number of ports. If I try to upload the service into the cloud I get the following error.
Validation error: Invalid number of input endpoints - current 1002,
max. 25
How can I get this work with cloud service?

Here is a solution based on Azure support answer.
You will need to define a public IP in the .cscfg file and upload it the cloud service.
<?xml version="1.0" encoding="utf-8"?>
<ServiceConfiguration serviceName="ILPIPSample" xmlns="http://schemas.microsoft.com/ServiceHosting/2008/10/ServiceConfiguration" osFamily="4" osVersion="*" schemaVersion="2014-01.2.3">
<Role name="WebRole1">
<Instances count="1" />
<ConfigurationSettings>
<Setting name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString" value="UseDevelopmentStorage=true" />
</ConfigurationSettings>
</Role>
<NetworkConfiguration>
<AddressAssignments>
<InstanceAddress roleName="WebRole1">
<PublicIPs>
<PublicIP name="MyPublicIP" domainNameLabel="WebPublicIP" />
</PublicIPs>
</InstanceAddress>
</AddressAssignments>
</NetworkConfiguration>
</ServiceConfiguration>
More info: https://learn.microsoft.com/en-us/azure/virtual-network/virtual-networks-instance-level-public-ip#manage-an-ilpip-for-a-cloud-services-role-instance
After that you can use nslookup to get the public IP assigned to the instance. If you have multiple instances, you need to change the 0 to 1, 2, 3 etc.
nslookup WebPublicIP.0.<Cloud Service Name>.cloudapp.net
Then you can open the local ports in Windows Firewall of the instance and you will be able to connect the local ports directly from the internet.
You can create a startup task to open the local ports in the cloud service firewall.
Following is an example of how to configure firewall rules. The startup task is executed every time the instance is rebooted/reimaged.
https://learn.microsoft.com/en-us/azure/cloud-services/cloud-services-startup-tasks-common#add-firewall-rules
Something like below:
netsh advfirewall firewall add rule name="TCP ports" protocol=TCP dir=in localport=1000-2000 action=allow

When a client connects to an FTP server using passive mode, it will make 2 connections.
One using port 21, and another for transferring data.
So it looks like you need to open a single port in ServiceDefinition.csdef and then create a port forwarding rule on the firewall (load balancer) to redirect all of the passive ports to that single port.
<Endpoints>
<InputEndpoint name="FTP2Azure.Command" protocol="tcp" port="21" localPort="9003" />
<InstanceInputEndpoint name="FTP2Azure.Passive" protocol="tcp" localPort="9002">
<AllocatePublicPortFrom>
<FixedPortRange max="21000" min="20000" />
</AllocatePublicPortFrom>
</InstanceInputEndpoint>
</Endpoints>
This is untested, but might help.

Related

Why does console apps use proxy by default?

I am currently having some issues with class library that doesn't behave as its console app.
The purpose of the console app is to send messages to an azure queue, which it does without any problem, and can see in ressource monitor that it makes calls through our web proxy and to our azure queue. This is done by default, I haven't told it anyway that it should use this proxy.
The class library on the other hand, does the same thing, but does not use the proxy, and therefore not able to send its data.
Both projects are identical, in the way they make the call to send a message, but for some reason is the console app, which intention is only to send a message, and library which intention is the same, act differently - why does the console app try to use proxy, and how do i force the class library to forcefully use the proxy?
conclusion:
How do i force a Microsoft.ServiceBus.Messaging.QueueClient.send
to use a proxy and not port 443
Per my knowledge, It is impossible to set the proxy while using service bus client.
The only connection options for Service Bus client are as following:
HTTP - port 80
HTTPS - port 443
TCP - 9350 to 9354
For more information we can refer to:
ConnectivityMode Enum
In your class library, please set the connectivity mode to Http as below code and try again:
ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Http;
Similar thread as yours: Azure Service Bus working behind proxy
To answer my own question.
I resolved the issue by creating a proxy.config , and add it to my app.config.
proxy.config format:
<?xml version="1.0"?>
<defaultProxy enabled="true">
<proxy autoDetect="False" proxyaddress="http://<proxyaddress>:<port>" />
<bypasslist>
<add address="localhost" />
</bypasslist>
</defaultProxy>
and add the proxy.config into my app.config as a system.net configuration:
<system.net>
<defaultProxy configSource="proxy.config" />
</system.net>

Reverse SSH Tunnel or TCP tunnel using the Remote Desktop Services API

I'm making an application that will allow for bidirectional desktop control for my own learning process, I don't like when standard RDP sessions lock the endpoints computer when a RDP session is in progress.
The setup is as follows:
SSH Server at home
Computer A at home.
Computer B at client endpoint.
The problem is that I cannot establish a connection with the connection string provided through the RDP API. I have attempted NAT UPNP port forwarding but I have ruled this out as a solution.
My current avenue of interest is to create a reverse ssh tunnel, and to have machine B tunnel into the ssh server, from that point Computer A will run:
ssh -l 3389:127.0.0.1:3389 credentials <-- Currently I'm doing this through putty. (Will use a ssh library to do this automatically)
Secondly it might also be possible to establish a connection via TCP:
Client B -> connects to Client A (Or the server links them and routes data)
Client B Generates RDP string
Client B Sends RDP string to client A
Client A attempts to connect to client Bs active RDP session.
..Here I hit a wall. Since the connection string generated points to one publicly routable address (IPv6) and the rest are temp IPv6 Addresses and the private IPv4 Address and the Link-Local address.
Computer B will then reverse tunnel into the ssh server:
ssh -R 6000:127.0.0.1:3389 credentials <-- Also through putty for testing.
This works if I were to open the built in remote desktop application and target
localhost:6000
but I want the client (computer B) to generate a connection string and send it via TCP (I can handle this internally, but have been just copy pasting the connection string manually. Still just for testing.)
Here is the connection string broken down into its tags:
<E>
<A KH="QHltZY9ISIdaMb3DNLVCVL8z22Q="
KH2="sha256:cEv4C57cmofFr8bJsttCX+taX5sWxWmgvSjpWRpTZ8U="
CE=
"MIIC4jCCAcqgAwIBAgIQSbu3zINwkqBB78x2uwORijANBgkqhkiG9w0BAQsFADAa
MRgwFgYDVQQDEw9QcmltYXJ5LURlc2t0b3AwHhcNMTgwNjA4MDY1MDU1WhcNMTgx
MjA4MDY1MDU1WjAaMRgwFgYDVQQDEw9QcmltYXJ5LURlc2t0b3AwggEiMA0GCSqG
SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDQ4tSRTPnCJuhCEJoOY8veHaFNg02Zmlg+
3eXZCH65Rejxlk1cmARknhw5+MuXTvka+oApQeWtZQBTpoE/KD1vaHOnQS0yLc8P
g6BvekNcoOY+6U9zOc1dP+EignJ8dHkSYc8Jr+k/OCfDTFoQZ/HVRUKHwd1ScNa2
YczGSrhboCevbSQxSTtcsI7H4tL6d58fdlp+lPXkLCkzo29IQCqKT5q94geXLvDa
t/U2rK6OcRFycEoNrwNPy7bwAnfIRTFDrLiQ8/6b28DrpPM7cJyM+K6cqsIOkkAd
gXPJNNMMKT3ej1KDTZ+UiLq3c9plPP7SUm9xLx7rhEct+zTf8RUhAgMBAAGjJDAi
MBMGA1UdJQQMMAoGCCsGAQUFBwMBMAsGA1UdDwQEAwIEMDANBgkqhkiG9w0BAQsF
AAOCAQEApU2ec3ZgWDHQ4/gsXv/wlpLeIMbeIpZrf9NpgqV6Ig3SR8PMldEgfGfz
XpB6C8mdoqCQglVWijr7M/QvZ9emrwNkfEDiKFuUHUETvdSD48jPJEwGtphhM58e
07O+y8VP5vrOn0uR/VTKx8M9OMBehDhu9SC1H3/NGqRfbGDleCbTz1KvAFKOJrCH
EvDHB+hyUFlapW/q/ZIMOefaYFYv/vnZvI6Sfy/NDKkSaOR0RBjrRA2dbmj6D0YU
EuU1FYwqmTtW8jlmoz2WfaLEli8QLkGx6lw1ej891g5AvvdD1UWVAUfssIlMl1YL
NSp6g8qJJrKtQvlCVUxwG4IH4ufb9w=="
ID="secretusername"
/>
<C>
<T ID="1" SID="0">
<L P="55114" N="fe80::710b:8671:823c:7aab%17"/>
<L P="55115" N="2604:282:3900:8eb0::af33"/>
<L P="55117"N="2604:282:3900:8eb0:710b:8779:28c3:7aab"/>
<L P="55117" N="2604:282:3900:8eb0:5dc5:b08e:de21:8bb8"/>
<L P="55118" N="10.0.0.14"/>
</T>
</C>
</E>
It may be important to note that many of the addresses listed between the < T > tag are redundant
My question is mainly: Is there a way that I can generate a connection string that will support reverse ssh or allow TCP to reroute data and provide an address that is publicly accessible, or is there a way I could append my own tag to the connection string: that would allow the connection to work.
The application works on local networks without error. I have searched for answers on the specific question that I am trying to solve any advice is appreciated, thank you.
TLDR
Machine A:
ssh -L 3389:127.0.0.1:3389 credentials
Machine B:
ssh -R 6000:127.0.0.1:3389 credentials
SSHD:
Connects the two tunnels
Machine A: Built in windows utility can target localhost:6000 and remotely connect to machine B.
Problems: don't want to use built in utility.
Cannot connect remotely using the connection string generated by machine B. As it only points to the local address of the device.
So, how can I generate a connection string that supports a publicly routable address, without having the port forward.

send message to azure service bus queue from web api

I am trying to get started with Azure Service Bus queues. following this article
https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-dotnet-get-started-with-queues
the only difference is that I am trying to do this from within a web api.
The error I get is:
No connection could be made because the target machine actively refused it 40.84.xxx.xx:443
I'd appreciate any help or pointers!
Note: Console app works just fine following the above guide.
Updated 7/24, this is the code in my action method:
try
{
var connectionString =
"Endpoint=sb://xxxxx-test.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=shared_access_key";
var queueName = "testqueue1";
var client =
QueueClient.CreateFromConnectionString(connectionString, queueName);
var message = new BrokeredMessage(eventMessage);
client.Send(message);
}
catch (Exception e)
{
//log exception
}
Update 7/25. I was able to make it work by setting defaultConfig entry as enabled in web.config:
<system.net>
<defaultProxy enabled="true"/>
</system.net>
No connection could be made because the target machine actively refused it 40.84.xxx.xx:443
Please check whether the outbound 443 port is blocked by your firewall.
Note: Console app works just fine following the above guide.
The default value of connectivity mode for Service Bus is AutoDetect. It will automatically selects between the Tcp and Http modes based on an auto-detection mechanism that probes whether either connectivity option is available for the current network environment. It maybe choose different modes for your Console App and Web API application. Try to set it to TCP explicitly in your Web API application before using the Service Bus Queue.
ServiceBusEnvironment.SystemConnectivity.Mode = ConnectivityMode.Tcp;
I was able to make it work by setting defaultConfig entry as enabled in web.config:
<system.net>
<defaultProxy enabled="true"/>
</system.net>

Silverlight 5 Opening Socket AccessDenied

I have a Silverlight 5 application trying establish a socket connection to a server as follows:
var targetEndpoint = new DnsEndPoint("subdomain.maindomain.com", 443);
var clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
var socketAsyncEventArgs = new SocketAsyncEventArgs {RemoteEndPoint = targetEndpoint};
socketAsyncEventArgs.Completed += AsyncConnectCallback;
clientSocket.ConnectAsync(socketAsyncEventArgs);
I have the following clientaccesspolicy.xml file at https://subdomain.maindomain.com/clientaccesspolicy.xml :
<access-policy>
<cross-domain-access>
<policy>
<allow-from http-request-headers="*" http-methods="*">
<domain uri="https://subdomain.maindomain.com"/>
<domain uri="*"/>
</allow-from>
<grant-to>
<resource path="/" include-subpaths="true"/>
<socket-resource port="4502" protocol="tcp"/>
</grant-to>
</policy>
</cross-domain-access>
</access-policy>
I am able to run a local instance of the Silverlight application from visual studio and can establish the socket connection, both running in-browser as well as out-of-browser. When I deploy the application, I am still able to connect using the out-of-browser version, but the in-browser version errors out with the following message:
AccessDenied: An attempt was made to access a socket in a way forbidden by its access permissions.
Within my local environment, where I am running from Visual studio, if I create an hosts file entry:
127.0.0.1 myapp.local
and update my localhost in-browser instance (running from VS) to use myapp.local, I can reproduce the same error, which suggests that the error occurs when the root domain is not localhost, regardless of where the application is hosted.
I have checked my firewall and antivirus software's event logs for signs that they could be blocking the connection request, but do not see any evidence of that.
Has anyone else experienced this issue and offer suggestions of what my problem could be?
According to the description of the problem as well as comments and the article "Relaxed Cross-Domain Access Restrictions", I think that most likely, the problem is with access restriction when the application is run in "in-browser" mode.
To verify that your application is run with trusted privileges you can check that property Application.HasElevatedPermissions is true.
Also, try to follow this guide How to: Enable Trusted Applications to Run Inside the Browser
Make sure that your server's firewall does not block "policy server" port 943
If you still unable to connect to server, try to change port that your service work on to some port that in range 4502 to 4534.
For Silverlight, you need a socket policy server in the mix.
See for details http://msdn.microsoft.com/en-us/library/cc645032%28v=vs.95%29.aspx for details.

ASP.NET WebApi SelfHost service fails on HTTP URL registration

I am trying to host an ASP.NET WebApi endpoint on an Azure worker role using the new Microsoft.AspNet.WebApi.SelfHost NuGet package. My worker's Run() code looks roughly like this:
// Endpoint is defined as in ServiceDefinition.csdef as
// HTTP, external port 8080, internal port 8080 (or 8081 - error both ways)
RoleInstanceEndpoint externalEndPoint =
RoleEnvironment.CurrentRoleInstance.InstanceEndpoints["Endpoint"];
string baseAddress= String.Format("http://{0}", externalEndPoint.IPEndpoint);
var maxsize = 1024 * 1024;
var config = new HttpSelfHostConfiguration(baseAddress)
{
MaxBufferSize = maxsize, MaxReceivedMessageSize = maxsize
};
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Create and open the server
var server = new HttpSelfHostServer(config);
server.OpenAsync().Wait();
// keep the worker thread alive
while (true)
Thread.Sleep(Timeout);
This works fine in the dev fabric, but when deploying to Azure, I get an AggregateException from the server.OpenAsync() call, containing the following exception stack:
[0] One or more errors occurred.
[1] HTTP could not register URL http://+:8081/. Your process does not have access rights to this namespace (see http://go.microsoft.com/fwlink/?LinkId=70353 for details).
[2] Access is denied
I'm just running a vanilla worker role and this seems to be the "hello world" of self-host...
The endpoint part of my ServiceDefinition.csdef looks like this:
<Endpoints>
<InputEndpoint name="Endpoint" protocol="http" port="8080" localPort="8081" />
</Endpoints>
The baseAddress that I get from the RoleEnvironment InstanceEndpoint looks legit - http://10.115.[X].[Y]:8081
I see the failure whether I use the same port/localPort (8080) or when I do a mapping, like the above.
It's clear that it's possible to host a conventional WCF service in a worker role in this way - is there any reason why ASP.NET WebApi SelfHost wouldn't work in this configuration?
By default, the RoleEntryPoint runs under a very minimal permission user account for security. As the error indicates, it is unable to reserve that port due to those permissions. You have two options here:
Run the Worker process as SYSTEM by adding the Runtime element to your role definition (i.e <Runtime executionContext="elevated"/>).
Create a startup script that runs elevated and reserves that port for you.
For playing around (and troubleshooting if it is a permission issue), doing #1 is a quick way to test it.
Edit: I seem to recall a permission issue with WCF and Windows Azure when doing wildcard reservations. It used to work fine when using the full hostname e.g.
host.AddServiceEndpoint(
typeof(IEchoService), new BasicHttpBinding(BasicHttpSecurityMode.None) { HostNameComparisonMode = HostNameComparisonMode.Exact }, "echo");
After half a dev-day experimenting with invoking netsh.exe from an elevated startup script to no avail, I gave up and ended up using the big hammer and taking Ryan's initial suggestion of running the entire worker role elevated:
<WorkerRole name="WorkerRole" vmsize="ExtraSmall">
<Runtime executionContext="elevated">
</Runtime>
</WorkerRole>
That solved all issues.
For reference, here is how I tried to allow HTTP registration for non-elevated user accounts (which never really worked):
In ServiceDefinition.csdef:
<Startup>
<Task executionContext="elevated" commandLine="startup\Install.cmd">
<Environment>
<Variable name="ENDPOINTPORT ">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/Endpoints/Endpoint[#name='Endpoint']/#port" />
</Variable>
</Environment>
</Task>
</Startup>
<Endpoints>
<InputEndpoint name="Endpoint" protocol="http" port="8080" localPort="8080" />
</Endpoints>
And in the startup script (startup\Install.cmd in my case):
netsh.exe http add urlacl url=http://+:%ENDPOINTPORT%/api user=everyone listen=yes delegate=yes
This is basically the solution that was recommended by the good folks working on AspNetWebApi (just a shorter way of doing what they recommend here), but unfortunately it didn't work for me - while the netsh command executed successfully and I was able to verify that the urlacl on the URL I am self-hosting on (http://+:8080/api/) is allowed by \Everyone, I was still getting the same permission error. If anyone figures out how to make this work when running the worker-role non-elevated, please post!
Add reference 'System.ServiceModel' to your project and with the 'config.HostNameComparisonMode = System.ServiceModel.HostNameComparisonMode.Exact;' you don't get the administrator privileges exception (access denied).

Categories

Resources