You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: Server enforced rpc invoke permission (#3731)
* Secure RpcMessage against SenderClientId spoofing
When a server receives an RpcMessage, it should update the SenderClientId to match the SenderId provided by the messaging manager. This is to prevent modified clients from spoofing their SenderClientId as other clients.
* Replaced RequireOwnership with a new RpcInvokePermission
that is respected from the server for both direct and
proxy RPCs.
* Replaced RequireOwnership with a new RpcInvokePermission
that is respected from the server for both direct and
proxy RPCs.
* Add missing switch case
* Another missing switch case
* Restore and deprecate RequireOwnership in favor of RpcInvokePermission
* Only do permission validations on server
context.SenderId will be the server for a client receiving the proxied message, so the checks will not be accurate. The checks are also unnecessary considering the checks have already been done by the server.
* ClientRpc properly assigned InvokePermission
Assigning ClientRpc.InvokePermission in the constructor was incorrect. Since we can check if it is a ClientRpc easily, I just do that in ILPP
* Move test files
* Get logic working and add tests
* Mark ServerRpc.RequireOwnership as deprecated
* small fixes
* Add back RpcAttributeParams.RequireOwnership
* Update CHANGELOG
* Add InvokePermission attribute when RequireOwnership is defined
* Fix whitespace
* fix __registerRpc breaking change
* second try at fixing breaking change
* Fix ilpp to log message if NetworkManager is not connected or listening
* Update com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc.md
Co-authored-by: Noel Stephens <[email protected]>
* Update com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc.md
Co-authored-by: Noel Stephens <[email protected]>
* Update com.unity.netcode.gameobjects/Documentation~/terms-concepts/ownership.md
Co-authored-by: Noel Stephens <[email protected]>
* Update log messages
* Fix naming in networkvariable.md doc
* Update com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc.md
Co-authored-by: Noel Stephens <[email protected]>
* Update com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc.md
Co-authored-by: Noel Stephens <[email protected]>
* Add invocation order documentation
---------
Co-authored-by: xmanning <[email protected]>
Co-authored-by: xmanning <[email protected]>
Co-authored-by: Noel Stephens <[email protected]>
Co-authored-by: Unity Netcode CI <[email protected]>
- Added new fields to the `SceneMap` struct when using Unity 6.3 or higher. These fields allow referencing scene handles via the new `SceneHandle` struct. (#3734)
15
16
@@ -25,11 +26,11 @@ Additional documentation and release notes are available at [Multiplayer Documen
25
26
26
27
### Deprecated
27
28
29
+
- Deprecated all `RequireOwnership` fields around the RPCs in favor of the `RpcInvokePermission`. (#3731)
28
30
- On Unity 6.5 some `SceneMap` fields that use an `int` to represent a `SceneHandle` are deprecated. (#3734)
29
31
30
32
### Removed
31
33
32
-
33
34
### Fixed
34
35
35
36
- Multiple disconnect events from the same transport will no longer disconnect the host. (#3707)
Copy file name to clipboardExpand all lines: com.unity.netcode.gameobjects/Documentation~/advanced-topics/message-system/rpc.md
+112-2Lines changed: 112 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,6 +1,6 @@
1
1
# RPC
2
2
3
-
Any process can communicate with any other process by sending a remote procedure call (RPC). As of Netcode for GameObjects version 1.8.0, the`Rpc` attribute encompasses server to client RPCs, client to server RPCs, and client to client RPCs.
3
+
Any process can communicate with any other process by sending a remote procedure call (RPC). The `Rpc` attribute is the recommended attribute to use when declaring RPC methods. The`Rpc` attribute's parameters define the receivers and execution rights for the RPC method.
|`Delivery`| Controls whether the delivery is reliable (default) or unreliable.<br /><br />Options: `RpcDelivery.Reliable` or `RpcDelivery.Unreliable`<br />Default: `RpcDelivery.Reliable`|
207
-
|`RequireOwnership`|If `true`, this RPC throws an exception if invoked by a player that does not own the object. This is in effect for server-to-client, client-to-server, and client-to-client RPCs - i.e., a server-to-client RPC will still fail if the server is not the object's owner.<br /><br />Default: `false`|
207
+
|`InvokePermission`|Sets an RPC's invocation permissions.<br /><br />Options:<br /> `RpcInvokePermission.Server` - This RPC throws an exception if invoked by a game client that is not the server.<br />`RpcInvokePermission.Owner` - This RPC throws an exception if invoked by a game client that does not own the object.<br />`RpcInvokePermission.Everyone` - This can be invoked by any connected game client.<br />Default: `RpcInvokePermission.Everyone`|
208
208
|`DeferLocal`| If `true`, RPCs that execute locally will be deferred until the start of the next frame, as if they had been sent over the network. (They will not actually be sent over the network, but will be treated as if they were.) This is useful for mutually recursive RPCs on hosts, where sending back and forth between the server and the "host client" will cause a stack overflow if each RPC is executed instantly; simulating the flow of RPCs between remote client and server enables this flow to work the same in both contexts.<br /><br />Default: `false`|
209
209
|`AllowTargetOverride`| By default, any `SendTo` value other than `SendTo.SpecifiedInParams` is a hard-coded value that cannot be changed. Setting this to `true` allows you to provide an alternate target at runtime, while using the `SendTo` value as a fallback if no runtime value is provided. |
210
210
@@ -215,6 +215,116 @@ There are a few other parameters that can be passed to either the `Rpc` attribut
215
215
|`Target`| Runtime override destination for the RPC. (See above for more details.) Populating this value will throw an exception unless either the `SendTo` value for the RPC is `SendTo.SpecifiedInParams`, or `AllowTargetOverride` is `true`.<br /><br />Default: `null`|
216
216
|`LocalDeferMode`| Overrides the `DeferLocal` value. `DeferLocalMode.Defer` causes this particular invocation of this RPC to be deferred until the next frame even if `DeferLocal` is `false`, while `DeferLocalMode.SendImmediate` causes the RPC to be executed immediately on the local machine even if `DeferLocal` is `true`. `DeferLocalMode.Default` does whatever the `DeferLocal` value in the attribute is configured to do.<br /><br />Options: `DeferLocalMode.Default`, `DeferLocalMode.Defer`, `DeferLocalMode.SendImmediate`<br />Default: `DeferLocalMode.Default`|
217
217
218
+
## Invocation order
219
+
220
+
Rpc message sent with `RpcDelivery.Reliable` will be sent and invoked on other game clients in the same order as they were called on the local game client.
Debug.Log($"client {rpcParams.Receive.SenderClientId} has opened door {doorId}");
227
+
228
+
// Server can handle door opening here
229
+
}
230
+
231
+
[Rpc(SendTo.Server)]
232
+
voidOpenChestRPC(intchestId, RpcParamsrpcParams)
233
+
{
234
+
Debug.Log($"client {rpcParams.Receive.SenderClientId} has opened chest {chestId}");
235
+
236
+
// Server can handle door opening here
237
+
}
238
+
239
+
voidUpdate()
240
+
{
241
+
if (IsClient&&Input.GetKeyDown(KeyCode.O))
242
+
{
243
+
OpenDoorRpc(1)
244
+
OpenDoorRpc(2)
245
+
OpenChestRpc(5)
246
+
}
247
+
248
+
// Other clients will log:
249
+
//
250
+
// "client 1 has opened door 1"
251
+
// "client 1 has opened door 2"
252
+
// "client 1 has opened chest 5"
253
+
}
254
+
```
255
+
256
+
> [!Warning]
257
+
> Invocation order is not guaranteed with nested RPC invocations that include targets that may invoke locally. Invocation order is also not guaranteed when using `RpcDelivery.Unreliable`
258
+
259
+
### Deferring local invocation
260
+
261
+
Invoking an RPC from within another RPC introduces the risk that the local RPC may invoke before messages are sent to other game clients. This will result in the RPC message for the inner RPC invocation being sent before the message for the outer RPC.
Debug.Log($"client {rpcParams.Receive.SenderClientId} is trying to open door {doorId}");
268
+
269
+
if (HasAuthority) {
270
+
// Authority handles opening the door here
271
+
272
+
// If the authority is invoking TryOpenDoorRpc locally before the authority has sent TryOpenDoorRpc to other clients, OpenDoorRpc will be sent before TryOpenDoorRpc.
Debug.Log($"client {rpcParams.Receive.SenderClientId} marked door {doorId} as open");
281
+
}
282
+
283
+
voidUpdate()
284
+
{
285
+
if (Input.GetKeyDown(KeyCode.O))
286
+
{
287
+
// Invocation of TryOpenDoorRpc and OpenDoorRpc may be inverted depending on the context in which TryOpenDoorRpc is invoked
288
+
TryOpenDoorRpc(20);
289
+
}
290
+
}
291
+
```
292
+
293
+
Use the RPC `LocalDeferMode` to resolve issue. Configuring the RPC to be deferred when invoked locally will ensure that any outer RPC messages are always sent before the inner function is invoked.
294
+
295
+
```csharp
296
+
// An RPC can be configured to defer the local invocation in the attribute definition
Copy file name to clipboardExpand all lines: com.unity.netcode.gameobjects/Documentation~/basics/networkvariable.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -145,7 +145,7 @@ This works the same way with dynamically spawned NetworkObjects.
145
145
146
146
The [synchronization and notification example](#synchronization-and-notification-example) highlights the differences between synchronizing a `NetworkVariable` with newly-joining clients and notifying connected clients when a `NetworkVariable` changes, but it doesn't provide any concrete example usage.
147
147
148
-
The `OnValueChanged` example shows a simple server-authoritative `NetworkVariable` being used to track the state of a door (that is, open or closed) using a non-ownership-based server RPC. With `RequireOwnership = false` any client can notify the server that it's performing an action on the door. Each time the door is used by a client, the `Door.ToggleServerRpc` is invoked and the server-side toggles the state of the door. When the `Door.State.Value` changes, all connected clients are synchronized to the (new) current `Value` and the `OnStateChanged` method is invoked locally on each client.
148
+
The `OnValueChanged` example shows a simple server-authoritative `NetworkVariable` being used to track the state of a door (that is, open or closed) using an RPCthat is sent to the server. Each time the door is used by a client, the `Door.ToggleStateRpc` is invoked and the server-side toggles the state of the door. When the `Door.State.Value` changes, all connected clients are synchronized to the (new) current `Value` and the `OnStateChanged` method is invoked locally on each client.
149
149
150
150
```csharp
151
151
publicclassDoor : NetworkBehaviour
@@ -180,7 +180,7 @@ public class Door : NetworkBehaviour
180
180
}
181
181
182
182
[Rpc(SendTo.Server)]
183
-
publicvoidToggleServerRpc()
183
+
publicvoidToggleStateRpc()
184
184
{
185
185
// this will cause a replication over the network
186
186
// and ultimately invoke `OnValueChanged` on receivers
0 commit comments