Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

PortInUseException thrown when Netty does not have the right to use configured port #19807

Closed
zhangyangyu opened this issue Jan 20, 2020 · 7 comments
Assignees
Labels
type: bug A general bug
Milestone

Comments

@zhangyangyu
Copy link

zhangyangyu commented Jan 20, 2020

I am using Spring Boot 2.2.2.RELEASE and tries to bind my embbed netty server to port 443 with a non root user. The application fails to start with message:

2020/01/20 09:29:09.465 [] [main] [DEBUG] report(LoggingFailureAnalysisReporter.java:37) - Application failed to start due to an exception
org.springframework.boot.web.server.PortInUseException: Port 443 is already in use
        at org.springframework.boot.web.embedded.netty.NettyWebServer.start(NettyWebServer.java:85)
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext$ServerManager.start(ReactiveWebServerApplicationContext.java:259)
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.startReactiveWebServer(ReactiveWebServerApplicationContext.java:138)
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.finishRefresh(ReactiveWebServerApplicationContext.java:130)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553)
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
        at com.huaweicloud.rms.RmsApplication.main(RmsApplication.java:21)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
        at org.springframework.boot.loader.Launcher.launch(Launcher.java:51)
        at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:52)

Spend some time trying to find the process using port 443 but there is no. The real cause is that with no more system config it's not allowed for a non root user to use port under 1024. I think the PortInUseException is misleading here and a PermissionException is more suitable.

@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged label Jan 20, 2020
@snicoll
Copy link
Member

snicoll commented Jan 20, 2020

Good catch @zhangyangyu, here is the underlying exception

Caused by: reactor.netty.ChannelBindException: Failed to bind on [0.0.0.0:443]
	Suppressed: java.lang.Exception: #block terminated with an error
		at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:139) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
		at reactor.core.publisher.Mono.block(Mono.java:1687) ~[reactor-core-3.3.2.RELEASE.jar:3.3.2.RELEASE]
		at reactor.netty.http.server.HttpServer.bindNow(HttpServer.java:129) ~[reactor-netty-0.9.4.RELEASE.jar:0.9.4.RELEASE]
		at reactor.netty.http.server.HttpServer.bindNow(HttpServer.java:112) ~[reactor-netty-0.9.4.RELEASE.jar:0.9.4.RELEASE]
		at org.springframework.boot.web.embedded.netty.NettyWebServer.startHttpServer(NettyWebServer.java:107) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.boot.web.embedded.netty.NettyWebServer.start(NettyWebServer.java:80) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext$ServerManager.start(ReactiveWebServerApplicationContext.java:246) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.startReactiveWebServer(ReactiveWebServerApplicationContext.java:125) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.finishRefresh(ReactiveWebServerApplicationContext.java:117) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:553) ~[spring-context-5.2.3.RELEASE.jar:5.2.3.RELEASE]
		at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.boot.SpringApplication.run(SpringApplication.java:315) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215) ~[spring-boot-2.3.0.BUILD-SNAPSHOT.jar:2.3.0.BUILD-SNAPSHOT]
		at com.example.testnetty.TestNettyApplication.main(TestNettyApplication.java:10) ~[classes/:na]
Caused by: io.netty.channel.unix.Errors$NativeIoException: bind(..) failed: Permission denied

@snicoll snicoll added type: bug A general bug and removed status: waiting-for-triage An issue we've not yet triaged labels Jan 20, 2020
@snicoll snicoll added this to the 2.1.x milestone Jan 20, 2020
@snicoll snicoll changed the title Misleading NettyWebServer bind exception PortInUseException thrown when Netty does not have the right to use configured port Jan 20, 2020
@RicardoRFaria
Copy link

RicardoRFaria commented Apr 15, 2020

Hi team, I'm willing to fix this issue, but I found some problems. Netty doesn't expose the "permission denied" info through an Exception, it just throw the NativeIoException

if (socketAddress instanceof InetSocketAddress) {
            InetSocketAddress addr = (InetSocketAddress) socketAddress;
            NativeInetAddress address = NativeInetAddress.newInstance(addr.getAddress());
            int res = bind(fd, address.address, address.scopeId, addr.getPort());
            if (res < 0) {
                throw newIOException("bind", res);
            }
...

Code from line 253. (https://github.com/netty/netty/blob/f17bfd0f64189d91302fbdd15103788bf9eabaa2/transport-native-unix-common/src/main/java/io/netty/channel/unix/Socket.java)

And even the native error code (-13), is converted to just a String in the message. As linked by @snicoll.

Do you think that a solution based on message "Permission Denied", is a good solution for now?
Or maybe a PR for Netty first, instead of making a validation based on a message.

@philwebb
Copy link
Member

@RicardoRFaria Which bit of the Netty code are you looking at? The exception @snicoll included is Errors$NativeIoException were as your snipped seems to throw a ConnectException.

@RicardoRFaria
Copy link

@philwebb The code that I linked before wasn't part of the problem. Sorry about that.
I edited the comment with the right code and more information, in the end, Netty doesn't expose the information of permission denied through an Exception or Error code, just the message.

@philwebb philwebb modified the milestones: 2.1.x, 2.1.14 Apr 21, 2020
@philwebb philwebb self-assigned this Apr 21, 2020
philwebb added a commit that referenced this issue Apr 21, 2020
Update classes that throw `PortInUseException` so that they also
include the cause. Prior to this commit the cause was not included
which could make diagnosing the real cause difficult.

See gh-19807
@philwebb
Copy link
Member

@RicardoRFaria Thanks for offer to help but I wanted to push something before we release 2.3.0.RC so I've made an attempt myself. In the end I decided the safest way was to look at the error code inside the Netty exception.

@RicardoRFaria
Copy link

@philwebb No problem. It was nice to see your solution.

@twhitmorenz
Copy link

Found this issue when trying to bind to an AWS machine's public IP - which doesn't actually exist as an interface on the machine, and thus failed with a fairly confusing "Port already in use" message.

Great to see the message is being clarified.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type: bug A general bug
Projects
None yet
Development

No branches or pull requests

6 participants